原创 KCTF 看雪学院
武林大会在即,看雪er们跟随武林少才的脚步齐聚华山,开启第五题《华山论剑》,一共有 4 支战队完成目标。
xtgo战队当仁不让,率先拿下本题,仅用时52092秒。 hzqmwne战队和雨落星沉战队紧追不舍,很快也成功攻破此题。
目前赛程已经过半,我们来看看目前场上的状况吧!攻击方排名前10如下:
大家在赛场上你追我赶,好不热闹!接下来我们一起来看看本题的“通关宝典”吧!
出题团队简介
本题出题战队为 ArmVMP :
专家点评
赛题设计思路
其中规则2的两组序列号如下:
serial:7C9815255BFE832D3F93140B
serial:17726331DA0fE737149c8202
设计思路
保护方法
解题思路
赛题解析
本赛题解析由看雪论坛 mb_mgodlfyn 给出:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <assert.h>
struct str {
const char *s;
int len;
};
//struct str global_name = {.s = "ed8b9244350d3644", .len = 16};
//struct str global_serial = {.s = "7C9815255BFE832D3F93140B", .len = 24};
struct str global_name = {.s = "KCTF", .len = 4};
struct str global_serial = {.s = "17726331DA0FE737149C8202", .len = 24};
//struct str global_serial = {.s = "17726331da0fe737149c8202", .len = 24};
struct JNINativeInterface_ {
unsigned int f[0x1000/4];
};
typedef struct JNIEnv_ {
struct JNINativeInterface_ *functions;
} JNIEnv;
void JNICALL_FindClass(JNIEnv *env, const char *name) {
printf("JNICALL_FindClass %s\n", name);
}
void JNICALL_NewStringUTF(JNIEnv *env, const char *utf) {
printf("%s %s\n", __func__, utf);
}
int JNICALL_GetMethodID(JNIEnv *env, void *clazz, const char *name, const char *sig) {
printf("%s %p %s %s\n", __func__, clazz, name, sig);
return 0x55555501;
}
void *JNICALL_CallObjectMethod(JNIEnv *env, void *obj, int methodID) {
assert(methodID == 0x55555501);
printf("%s %p %x\n", __func__, obj, methodID);
return obj;
}
int JNICALL_GetArrayLength(JNIEnv *env, struct str *array) {
printf("%s %p\n", __func__, array);
return array->len;
}
unsigned char *JNICALL_GetByteArrayElements(JNIEnv *env, struct str *array, int isCopy) {
printf("%s %p %d\n", __func__, array, isCopy);
return array->s;
}
void JNICALL_ReleaseByteArrayElements(JNIEnv *env, void *array, void *elems, int mode) {
printf("%s %p %p %d\n", __func__, array, elems, mode);
}
void *got_malloc(int size) {
void *r = malloc(size);
printf("%s %d %p\n", __func__, size, r);
return r;
}
void got_free(void *p) {
printf("%s\n", __func__);
free(p);
}
void got_memset(char *p, int n, int count) {
printf("%s %p %d %d\n", __func__, p, n, count);
memset(p, n, count);
}
void bp(void) {
;
}
void stack_chk_guard(void) {
printf("%s\n", __func__);
}
void imp___gnu_Unwind_Find_exidx(void) {
printf("%s\n", __func__);
}
void cxa_call_unexpected(void) {
printf("%s\n", __func__);
}
int main(void) {
int fd = open("libhello-jni.so", O_RDONLY);
unsigned char *fmem = mmap(NULL, 0x7000, PROT_READ, MAP_PRIVATE, fd, 0);
unsigned char *mem = mmap(0xdead0000, 0x8000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
memcpy(mem, fmem, 0x2b13);
memcpy(mem+0x3e8c, fmem+0x2e8c, 0x1a8);
memcpy(mem+0x5000, fmem+0x4000, 0x26bc);
munmap(fmem, 0x7000);
close(fd);
*(unsigned int *)(mem+0x3f98) = mem+0x1034+1; // xxxxxxxxxx2+1
*(unsigned int *)(mem+0x3f9c) = stack_chk_guard;
*(unsigned int *)(mem+0x3fb8) = imp___gnu_Unwind_Find_exidx;
*(unsigned int *)(mem+0x3fc4) = cxa_call_unexpected;
*(unsigned int *)(mem+0x3fc8) = mem+0x3f98; // _GLOBAL_OFFSET_TABLE_@got
*(unsigned int *)(mem+0x3fa0) = mem+0x10e4+1; // Java_com_example_hellojni_HelloJni_stringFromJNI_ptr+1
*(unsigned int *)(mem+0x3fa4) = mem+0x4004; // f_data_key_dllink
*(unsigned int *)(mem+0x3fa8) = mem+0x401c; // f_sucess
*(unsigned int *)(mem+0x3fdc) = got_malloc; // malloc@got
*(unsigned int *)(mem+0x3fe0) = got_memset; // memset@got
*(unsigned int *)(mem+0x3fe4) = got_free; // free@got
for (int i = 0x3f98; i < 0x4000; i+=4) {
if (*(unsigned int *)(mem+i) == 0) {
//*(unsigned int *)(0x77770000+i) = i;
}
}
struct JNINativeInterface_ jnii = {.f = {0}};
for(int i = 0; i < 0x100; i++) {
jnii.f[i] = 0x11110000+i*4;
}
jnii.f[0x18/4] = JNICALL_FindClass;
jnii.f[0x29c/4] = JNICALL_NewStringUTF;
jnii.f[0x84/4] = JNICALL_GetMethodID;
jnii.f[0x88/4] = JNICALL_CallObjectMethod;
jnii.f[0x2ac/4] = JNICALL_GetArrayLength;
jnii.f[0x2e0/4] = JNICALL_GetByteArrayElements;
jnii.f[0x300/4] = JNICALL_ReleaseByteArrayElements;
JNIEnv env;
env.functions = &jnii;
printf("&global_name: %p, &global_serial: %p\n", &global_name, &global_serial);
bp();
((void (*)(int, int, int, int, int))(mem+0x10e4+1))(&env, 0xaaaa, &global_name, &global_serial, 0xdddd);
return 0;
}
LOAD:00005D04 ; ---------------------------------------------------------------------------
LOAD:00005D04 CODE16
LOAD:00005D04 B sub_5D10 ; Branch
LOAD:00005D04 ; ---------------------------------------------------------------------------
LOAD:00005D06 CODE32
LOAD:00005D06 DCW 0xBF00
LOAD:00005D08 DCD 8, 0x30D00
LOAD:00005D10 CODE16
LOAD:00005D10
LOAD:00005D10 ; =============== S U B R O U T I N E =======================================
LOAD:00005D10
LOAD:00005D10 ; Attributes: thunk
LOAD:00005D10
LOAD:00005D10 sub_5D10 ; CODE XREF: LOAD:00005D04↑j
LOAD:00005D10 BX PC ; Branch to/from Thumb mode
LOAD:00005D10 ; ---------------------------------------------------------------------------
LOAD:00005D12 DCB 1
LOAD:00005D13 DCB 0
LOAD:00005D13 ; End of function sub_5D10
LOAD:00005D13
LOAD:00005D14 CODE32
LOAD:00005D14
LOAD:00005D14 ; =============== S U B R O U T I N E =======================================
LOAD:00005D14
LOAD:00005D14
LOAD:00005D14 sub_5D14 ; CODE XREF: sub_5D10↑j
LOAD:00005D14
LOAD:00005D14 var_FC = -0xFC
LOAD:00005D14
LOAD:00005D14 STR PC, [SP,#var_FC] ; Store to Memory
LOAD:00005D18 B sub_7270 ; Branch
LOAD:00005D18 ; End of function sub_5D14
LOAD:00005D1C ; ---------------------------------------------------------------------------
LOAD:00005D1C CODE16
LOAD:00005D1C B sub_5D28 ; Branch
LOAD:00005D1C ; ---------------------------------------------------------------------------
LOAD:00005D1E CODE32
几个关键的位置:
前期调试分析过程很漫长,但最终找出serial很简单:
往期解析
1. 看雪·深信服 2021 KCTF 春季赛 | 第二题设计思路及解析
主办方
第六题正在火热进行中,
球分享
球点赞
球在看