-
-
[原创][原创]2019KCTF总决赛 第七题:东北奇闻 - 脱机算法
-
发表于: 2019-12-19 14:12 5139
-
大致流程,脱机算法搞出来,然后分析
1-题目改了androidx.appcompat.app.AppCmpatActivity; 在里面找到showAssist native
2-SO解密了2部分内存数据块,存放起来
3-手动抠出算法,内存加密函数2个,func1和func2 ,函数1直接可看,函数2 肉眼解一下 ollvm就可以找出算法
4-第二个函数func2是char加密,实际是个映射表,跑一遍255个字节就出来了
5-最后的比较函数根据第三步的表倒推出最原始的输入数据的一组地址
/**********************************************找到对应的判断函数*********************************************************/
registernative 对应的函数地址是 0x19f81
ida修改下sp,可以看到函数了
之后就是 通过 jni调用GetText获取输入值,这里假设先输入 gabcdefghijklmn来测试
最终根据JNI函数来找到内存字符串
跟着字符串走到 0x9ce4处,这里是把输入的字符 每隔8个传入,开头是解密一块内存,但是后边的运算是要用到这4个数组,
比较运气好的是 是连续的 大概0xC00长度位一块
所以直接dump保存下来到文件,后面解析用到
import idaapi start_address = 0xAEE7B010 data_length = 0xc00 * 4 data = idaapi.dbg_read_memory(start_address , data_length) fp = open('/Users/beita/tmp/pediy/ctfq4/barr_dump_bin', 'wb') fp.write(data) fp.close()
这部分代码用来第一次进行计算, 大致是前4个字节和猴子哥字节分别保存起来,然后用 字节对应到上面的4个数组元素来进行 加减异或运算 ,然后ROR4 再运算 ,大概是4组数据
处理完之后 ,把加密后的2个数据 ,v37和v35的值传入到 DF18进行第二个加密
第二个加密函数分析 代码 在附件 abc.c文件里
这部分代码在附件里 像是被ollvm的,,不过肉眼过一下流程看看还好
import idaapi start_address = 0xAEE7B010 data_length = 0xc00 * 4 data = idaapi.dbg_read_memory(start_address , data_length) fp = open('/Users/beita/tmp/pediy/ctfq4/barr_dump_bin', 'wb') fp.write(data) fp.close()
这部分代码用来第一次进行计算, 大致是前4个字节和猴子哥字节分别保存起来,然后用 字节对应到上面的4个数组元素来进行 加减异或运算 ,然后ROR4 再运算 ,大概是4组数据
处理完之后 ,把加密后的2个数据 ,v37和v35的值传入到 DF18进行第二个加密
第二个加密函数分析 代码 在附件 abc.c文件里
这部分代码在附件里 像是被ollvm的,,不过肉眼过一下流程看看还好
824行 先保存参数到v70 params1=0x5d =================================================此时的param1是v104 也就是0x5d ======================================================= 314行 然后算出v111 v111 = params1 >> 6 = 1 v112 = params1 & 3 = 1 1024行 v118 = (params1 >> 4) & 3 ^ v116; 此处的116是上一个的112 此处v118=0 v119 = (params1 >> 2) & 3 ^ v115; 此处的115是上一个的111 此处v119=2 v29 = -1811835405; 484行 计算 v101 LODWORD(v101) = 2 * params & 0xAA; HIDWORD(v101) = ((unsigned int)params >> 1) & 0x55; v101= 400000aa 64位的 781行 算出v20 = 0xae 然后0xae保存起来、 v20 = HIDWORD(v101) | v101; 根据v20 算出v103 v102 v103 = v20 & 0xCC; 0x8c v102 = 4 * v20 & 0xCC; 0x88 1191行 根据v103 v102算出 V104 v105 v104 = v102 | (v103 >> 2); 0xab v105 = o * (o - 1) & 1; 0 967行 对一开始的一个传入的0x5d的那个参数值重新赋值 后面是几个保存传入参数的变量都进行赋值 =================================================此时的param1是v104 也就是0xab ======================================================= 314行 然后算出v111 v111 = params1 >> 6 = 2 v112 = params1 & 3 = 3 v116 = v112 v117=v111 ^ v112 1024行 v118 = (params1 >> 4) & 3 ^ v116; 此处的116是上一个的112 此处v118=1 v119 = (params1 >> 2) & 3 ^ v115; 此处的115是上一个的111 此处v119=2 1141行 算出 v124 LODWORD(v124) = v117 << 6; HIDWORD(v124) = 16 * v119 & 0x30; 354行 算出v125 v125 = v124 | HIDWORD(v124); 终于来到了 1207行 计算返回结果 v53 = v125 | 4 * v116 & 0xFFFFFFC; v58 = v53 & v118; v59 = v53 ^ (unsigned __int8)v118; v60 = v59 | v58; 然后反转 v60 也就是 0xd4反转0x4d
继续往下跟 最终结果是通过 strcmp来比较的
可以看到只要前半部分能对应上就可以通过
然后 68dd8a0f7065609e3106fb2bb1059423e80fb1347318ffeb83b8a074a7e6c9cf
找出这个字符串
因为第二个加密算法已经分析过, 传入是 uint8_t类型 ,输出也是uint_8t类型,所以,这里可以搞一个映射表
typedef struct { uint8_t orig; uint8_t enc; } CHAR_TABLE; void create_table() { char sss[2048]; memset(sss, 0, 2048); char *key = "68dd8a0f7065609e3106fb2bb1059423e80fb1347318ffeb83b8a074a7e6c9cfd9\n"; size_t right_key_len = strlen(key) / 2 + 1; uint8_t after_key_elem[right_key_len]; // 加密后的key数组 uint8_t before_key_elem[right_key_len]; // 输入之前的值 memset(after_key_elem, 0, right_key_len); memset(before_key_elem, 0, right_key_len); char *p = key; for (int i = 0; i < right_key_len; i++) { char k_tmp[3]; memset(k_tmp, 0, 3); memcpy(k_tmp, p, 2); after_key_elem[i] = strtol(k_tmp, NULL, 16); p += 2; } CHAR_TABLE enc_table[256]; for (int i = 0; i < 256; i++) { enc_table[i].orig = i; enc_table[i].enc = encrypt2(i); } for (int i = 0; i < right_key_len; i++) { uint8_t v1 = after_key_elem[i]; // 用加密后的每个元素取在映射表里遍历查找 for (int k = 0; k < 256; k++) { CHAR_TABLE c = enc_table[k]; if (v1 == c.enc) { before_key_elem[i] = c.orig; break; } } } printf("gogogo\n"); printf("\n%s\n", sss); }
然后得到 对应的表
68dd8a0f7065609e3106fb2bb1059423e80fb1347318ffeb83b8a074a7e6c9cfd9 字符串对应原始表在这里查找
运行一下看看脱机效果
比如这里我输入的是 gabcdefghijklmn 在手机上看 第一部分加密函数的结果
用两组数据
*******************************************手机上*****************************************************************
输入 后先截取前8字节 gabcdefg ,看结果下图, 传入 df18的是 0x5d2680eb >> 24 那么就是说
gabcdefg被加密成 0x5d2680eb 然后传入高8位字节 也就是 0x5d
结果是输入0x5d 输出0xd4
******************************************* 脱机代码在附件*********************************************************************
看到输入gabcdefg 测试,然后
加密0x5d 输出0xd4,
加密0x26输出 0xac
最后加密的结果也是在这里计算结束后后和 strcmp的2个参数 就是用的这里的第二个加密函数的结果来进行比较的,说明脱机加密是对的
这里证是对脱机的传入的值进行比较,说明算法是对的
*********************************************************************************************************************
脱机算法 如下 ,具体内容在附件里, 代码可以运行,改一下文件路径就可以运行
824行 先保存参数到v70 params1=0x5d =================================================此时的param1是v104 也就是0x5d ======================================================= 314行 然后算出v111 v111 = params1 >> 6 = 1 v112 = params1 & 3 = 1 1024行 v118 = (params1 >> 4) & 3 ^ v116; 此处的116是上一个的112 此处v118=0 v119 = (params1 >> 2) & 3 ^ v115; 此处的115是上一个的111 此处v119=2 v29 = -1811835405; 484行 计算 v101 LODWORD(v101) = 2 * params & 0xAA; HIDWORD(v101) = ((unsigned int)params >> 1) & 0x55; v101= 400000aa 64位的 781行 算出v20 = 0xae 然后0xae保存起来、 v20 = HIDWORD(v101) | v101; 根据v20 算出v103 v102 v103 = v20 & 0xCC; 0x8c v102 = 4 * v20 & 0xCC; 0x88 1191行 根据v103 v102算出 V104 v105 v104 = v102 | (v103 >> 2); 0xab v105 = o * (o - 1) & 1; 0 967行 对一开始的一个传入的0x5d的那个参数值重新赋值 后面是几个保存传入参数的变量都进行赋值 =================================================此时的param1是v104 也就是0xab ======================================================= 314行 然后算出v111 v111 = params1 >> 6 = 2 v112 = params1 & 3 = 3 v116 = v112 v117=v111 ^ v112 1024行 v118 = (params1 >> 4) & 3 ^ v116; 此处的116是上一个的112 此处v118=1 v119 = (params1 >> 2) & 3 ^ v115; 此处的115是上一个的111 此处v119=2 1141行 算出 v124 LODWORD(v124) = v117 << 6; HIDWORD(v124) = 16 * v119 & 0x30; 354行 算出v125 v125 = v124 | HIDWORD(v124); 终于来到了 1207行 计算返回结果 v53 = v125 | 4 * v116 & 0xFFFFFFC; v58 = v53 & v118; v59 = v53 ^ (unsigned __int8)v118; v60 = v59 | v58; 然后反转 v60 也就是 0xd4反转0x4d
继续往下跟 最终结果是通过 strcmp来比较的
可以看到只要前半部分能对应上就可以通过
然后 68dd8a0f7065609e3106fb2bb1059423e80fb1347318ffeb83b8a074a7e6c9cf
找出这个字符串
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2019-12-26 19:39
被贝a塔编辑
,原因: 图搞错了
赞赏
他的文章
谁下载
无
谁下载
无
谁下载
无
看原图
赞赏
雪币:
留言: