样本来自看雪3W班5月题
本题主要是还原so的算法函数,关键算法函数很好定位,主要还原方法是frida
+ida调试
+ida trace
1、找到对应产生结果的函数public native byte[] e(byte[] arg1)
:
public class MainActivity extends AppCompatActivity { static { System.loadLibrary("native-lib"); } public native byte[] d(byte[] arg1) { } public native byte[] e(byte[] arg1) { } @Override // androidx.appcompat.app.AppCompatActivity protected void onCreate(Bundle arg3) { super.onCreate(arg3); this.setContentView(0x7F09001C); // layout:activity_main TextView v3 = (TextView)this.findViewById(0x7F070061); // id:sample_text StringBuilder v0 = new StringBuilder(); v0.append("pediy_imyang_"); v0.append(RandomStringUtils.randomAlphabetic(10)); v3.setText(ByteString.of(this.e(v0.toString().getBytes())).hex()); } }
2、固定入参,打印参数
function hook_java(){ Java.perform(function () { //org.apache.commons.lang3.RandomStringUtils.randomAlphabetic(int): java.lang.String var RandomStringUtils = Java.use("org.apache.commons.lang3.RandomStringUtils"); RandomStringUtils.randomAlphabetic.overload('int').implementation = function(arg){ var result = this.randomAlphabetic(arg); // console.log("org.apache.commons.lang3.RandomStringUtils.randomAlphabetic:", result); result = "lXcaTALmow"; return result; } //com.kanxue.ollvm5.MainActivity.encryt(byte[]): byte[] var ByteString = Java.use("com.android.okhttp.okio.ByteString"); var MainActivity = Java.use("com.kanxue.ollvm5.MainActivity"); MainActivity.e.implementation = function(arg){ var result = this.e(arg); console.log("com.kanxue.ollvm5.MainActivity arg:", ByteString.of(arg).hex()); console.log("com.kanxue.ollvm5.MainActivity result:", ByteString.of(result).hex()); return result; } }); }
得到结果:
com.kanxue.ollvm5.MainActivity arg: 70656469795f696d79616e675f6c58636154414c6d6f77 com.kanxue.ollvm5.MainActivity result: 797903090001a4b8b6c89eb47f4f29b44d47c7382f851ad57618f9b820c5d55298cb5f941c8c
3、ida打开对应so,找到jbyteArray __fastcall Java_com_kanxue_ollvm5_MainActivity_e(JNIEnv *env_, __int64 a2, jbyteArray ary)
函数,hook发现sub_184EC
调用三次,其中第三次的arg1为结果函数
sub_184EC(&arg0, arg1, arg2); `
查找sub_184EC
引用,找到函数sub_13CE4
__int64 __fastcall sub_13CE4(__int64 result, unsigned int a2, __int64 a3, unsigned int a4, __int64 output)
4、hook sub_184EC
, 根据结果可知参数类型, 第2个参数是input,第5个参数是ouput, 即sub_184EC
为关键算法函数
//13CE4 var addr_13CE4 = base.add(0x13CE4); var arg13CE4_0; var arg13CE4_1; var arg13CE4_4; Interceptor.attach(addr_13CE4, { onEnter: function (args) { //var r2 = this.context.r2; arg13CE4_0 = args[0]; arg13CE4_1 = args[1]; arg13CE4_4 = args[4]; console.log("addr_13CE4 onEnter args0", hexdump(args[0])); //input console.log("addr_13CE4 onEnter args1", args[1]); //inputlen console.log("addr_13CE4 onEnter args4", hexdump(args[4])); }, onLeave: function (retval) { console.log("addr_13CE4 onLeave args0", hexdump(arg13CE4_0)); console.log("addr_13CE4 onLeave args1", arg13CE4_1); console.log("addr_13CE4 onLeave args4", hexdump(arg13CE4_4)); // console.log("addr_13CE4 retval", hexdump(arg1)); } });
frida写一个主动调用,trace一下
function call_e() { //主动调用函数 //com.kanxue.ollvm5.MainActivity.e(byte[]): byte[] Java.perform(function () { var MainActivity = Java.use("com.kanxue.ollvm5.MainActivity"); Java.choose("com.kanxue.ollvm5.MainActivity", { onMatch: function (instance) { //pediy_imyang_lXcaTALmow var buffer = Java.array('byte', [0x70, 0x65, 0x64, 0x69, 0x79, 0x5f, 0x69, 0x6d, 0x79, 0x61, 0x6e, 0x67, 0x5f, 0x6c, 0x58, 0x63, 0x61, 0x54, 0x41, 0x4c, 0x6d, 0x6f, 0x77]) var result = instance.e(buffer); var ByteString = Java.use("com.android.okhttp.okio.ByteString"); console.log(ByteString.of(result).hex()) }, onComplete: function () { } }); }); }
从trace的结果来看只看到input没看到output
再返回仔细看,尝试hook sub_13808试试
[AOSP on msm8996::com.kanxue.ollvm5]-> android_dlopen_ext: /data/app/com.kanxue.ollvm5-BHVsEeMGCcVFJqvmRywKWw==/lib/arm64/libnative-lib.so addr_13CE4 onEnter args0 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 71103c3940 70 65 64 69 79 5f 69 6d 79 61 6e 67 5f 6c 58 63 pediy_imyang_lXc 71103c3950 61 54 41 4c 6d 6f 77 00 63 74 69 76 69 74 79 00 aTALmow.ctivity. 71103c3960 60 74 22 10 71 00 00 00 a0 3a 3c 10 71 00 00 00 `t".q....:<.q... 71103c3970 d8 2e 07 05 71 00 00 00 7a 69 70 3a 00 00 00 00 ....q...zip:.... 71103c3980 40 39 3c 10 71 00 00 00 78 2f f9 1f b9 bb 45 f9 @9<.q...x/....E. 71103c3990 88 61 d2 6f 00 00 00 00 01 69 70 3a 0d 00 00 00 .a.o.....ip:.... 71103c39a0 e0 38 3c 10 71 00 00 00 c2 0c ec de f4 c9 52 69 .8<.q.........Ri 71103c39b0 b0 72 20 f7 70 00 00 00 01 69 70 3a 0e 00 00 00 .r .p....ip:.... 71103c39c0 e0 39 3c 10 71 00 00 00 9c 37 53 f8 65 b6 7c 4b .9<.q....7S.e.|K 71103c39d0 e0 72 20 f7 70 00 00 00 01 69 70 3a 0f 00 00 00 .r .p....ip:.... 71103c39e0 80 39 3c 10 71 00 00 00 3c 06 6b 29 07 5f ca 6f .9<.q...<.k)._.o 71103c39f0 10 73 20 f7 70 00 00 00 01 69 70 3a 10 00 00 00 .s .p....ip:.... 71103c3a00 c0 39 3c 10 71 00 00 00 db 0c 87 26 01 e5 1f 47 .9<.q......&...G 71103c3a10 40 73 20 f7 70 00 00 00 01 69 70 3a 11 00 00 00 @s .p....ip:.... 71103c3a20 60 39 3c 10 71 00 00 00 93 20 5d c7 0a 4f 29 a9 `9<.q.... ]..O). 71103c3a30 78 c7 c5 6f 00 00 00 00 e0 c9 38 10 71 00 00 00 x..o......8.q... addr_13CE4 onEnter args1 0x17 addr_13808 onEnter args0 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 79ff4fd210 77 77 77 2e 70 65 64 69 79 2e 63 6f 6d 26 6b 61 www.pediy.com&ka 79ff4fd220 6e 78 75 65 00 00 00 00 79 79 00 00 00 00 00 00 nxue....yy...... 79ff4fd230 62 61 73 69 63 5f 73 74 72 69 6e 67 00 00 00 00 basic_string.... 79ff4fd240 61 6c 6c 6f 63 61 74 6f 72 3c 54 3e 3a 3a 61 6c allocator<T>::al addr_13808 onEnter args1 0x14 addr_13808 onLeave args2 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 7fdcb5fe70 31 f5 f5 f5 f9 43 4d 51 a8 fb 31 b6 ef 7f f7 3c 1....CMQ..1....< 7fdcb5fe80 40 ba 21 9d 7a 00 00 00 17 00 00 00 00 00 00 00 @.!.z........... 7fdcb5fe90 46 9d 4c 18 7a 00 00 00 00 00 00 00 09 00 00 00 F.L.z........... 7fdcb5fea0 60 75 49 18 7a 00 00 00 40 9d 4c 18 17 00 00 00 `[email protected]..... 7fdcb5feb0 10 d2 4f ff 79 00 00 00 14 00 00 00 00 00 00 00 ..O.y........... addr_172D0 onEnter args0 0xb6cff93c addr_172D0 onLeave retval 0xcff93cb6 addr_172D0 onEnter args0 0xb6ef9f85 addr_172D0 onLeave retval 0x9f85b6ef addr_172D0 onEnter args0 0xcf506afb addr_172D0 onLeave retval 0xfbcf506a addr_172D0 onEnter args0 0x3ca8f563 addr_172D0 onLeave retval 0xa8f5633c addr_172D0 onEnter args0 0x63636363 addr_172D0 onLeave retval 0x63636363 addr_172D0 onEnter args0 0x63636363 addr_172D0 onLeave retval 0x63636363 addr_13CE4 onLeave args4 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 71102c8e70 79 79 03 09 00 01 a4 b8 b6 c8 9e b4 7f 4f 29 b4 yy...........O). 71102c8e80 4d 47 c7 38 2f 85 1a d5 76 18 f9 b8 20 c5 d5 52 MG.8/...v... ..R 71102c8e90 98 cb 5f 94 1c 8c 38 3c 55 0b 00 00 00 00 00 00 .._...8<U....... 71102c8ea0 4a 61 76 61 5f 63 6f 6d 5f 6b 61 6e 78 75 65 5f Java_com_kanxue_ 71102c8eb0 6f 6c 6c 76 6d 35 5f 4d 61 69 6e 41 63 74 69 76 ollvm5_MainActiv 71102c8ec0 69 74 79 5f 65 00 00 00 56 0b 00 00 00 00 00 00 ity_e...V....... 71102c8ed0 80 a2 2c 10 71 00 00 00 71 54 b6 27 19 57 c7 d8 ..,.q...qT.'.W.. 71102c8ee0 00 00 00 00 00 00 00 00 db d0 cf 94 71 00 00 00 ............q... 71102c8ef0 0e 00 00 00 00 00 00 00 57 0b 00 00 00 00 00 00 ........W....... 71102c8f00 10 a6 2c 10 71 00 00 00 3b 29 67 2f d8 63 3f 36 ..,.q...;)g/.c?6 71102c8f10 00 00 00 00 00 00 00 00 01 d1 cf 94 71 00 00 00 ............q... 71102c8f20 13 00 00 00 00 00 00 00 b8 0b 00 00 00 00 00 00 ................ 71102c8f30 00 8f 2c 10 71 00 00 00 12 6d 28 cd 75 ae c6 d4 ..,.q....m(.u... 71102c8f40 00 00 00 00 00 00 00 00 25 d1 cf 94 71 00 00 00 ........%...q... 71102c8f50 18 00 00 00 00 00 00 00 c2 0b 00 00 00 00 00 00 ................ 71102c8f60 90 95 2c 10 71 00 00 00 52 af da eb a8 27 dd ed ..,.q...R....'.. com.kanxue.ollvm5.MainActivity arg: 70656469795f696d79616e675f6c58636154414c6d6f77 com.kanxue.ollvm5.MainActivity result: 797903090001a4b8b6c89eb47f4f29b44d47c7382f851ad57618f9b820c5d55298cb5f941c8c
一步一步调试,发现第一轮最先生成的是
79 79 03 09 00 01 51 4D 43 F9 B6 CF F9 3C B6 EF 9F 85 CF 50 6A FB EF 20 83 29 3C A8 F5 63 63 63 63 63 63 63 63 63
然后才生成结果
79 79 03 09 00 01 a4 b8 b6 c8 9e b4 7f 4f 29 b4 4d 47 c7 38 2f 85 1a d5 76 18 f9 b8 20 c5 d5 52 98 cb 5f 94 1c 8c
根据trace + 第一轮生成结果比对 还原出最终算法代码如下
static char keytb_42210[] = { 0x77, 0x77, 0x77, 0x2e, 0x70, 0x65, 0x64, 0x69, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x26, 0x6b, 0x61, 0x6e, 0x78, 0x75, 0x65, 0x00 }; static char keytbde[] = { 0x31, 0xf5, 0xf5, 0xf5, 0xf9, 0x43, 0x4d, 0x51, 0xa8, 0xfb, 0x31, 0xb6, 0xef, 0x7f, 0xf7, 0x3c, 0x40, 0xba, 0x21, 0x9d, 0x7a, 0x00 }; static char byte_42228[] = {0x79, 0x79, 0x00, 0x00}; static char byte_42108[] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; void sub_13808(char* tb, int tblen, char* output){ //本函数从keytb_42210 解析出 keytbde } int REV(int val){ return (((val << 24) & 0xFF000000) | ((val << 8) & 0x00FF0000) | ((val >> 8) & 0x0000FF00) | ((val >> 24) & 0x000000FF)); } int keygen_13CE4(const char* input, unsigned int inputlen, char* tb, unsigned int tblen, char* output){ char* o13808 = new char[0x20]; sub_13808(tb, tblen, o13808); output[0] = byte_42228[0]; //LOGD("%0x %0x",0, output[0]); output[1] = byte_42228[1]; output[2] = 0x03; output[3] = (-inputlen ^ 0xFFFFFFF0) & -inputlen;; output[4] = 0; output[5] = 1; //LOGD("%0x %0x",3, output[3]); //LOGD("%0x %0x",4, output[4]); for(int i = 6; i <= 0x25; i++){ int index = input[i - 6]; if(i - 6 >= inputlen){ output[i] = byte_42108[0]; //LOGD("%0x %0x",i, output[i]); continue; } output[i] = byte_42108[index]; //LOGD("%0x %0x",i, output[i]); } for(int i = 0; i < tblen; i++){ int index = tb[i]; tb[i] = byte_42108[index]; //LOGD("tb %0x %0x",i, tb[i]); } for(int i = 0; i <= (0x25 - 0x6)/4; i++){ unsigned int tmp1 = 0; memcpy(&tmp1, keytbde+4*(i%4), sizeof(int)); //LOGD("tmp1 %0x", tmp1); unsigned int tmp2 = 0; memcpy(&tmp2, output + i*4 + 6, sizeof(int)); //LOGD("tmp2 %0x", tmp2); tmp2 = (tmp2 >> 8*(i%4)) | (tmp2 << 32 - 8*(i%4)); //LOGD("tmp2 %0x", tmp2); tmp2 = REV(tmp2); int outputtmp = REV(tmp1 & ~tmp2 | tmp2 & ~tmp1); LOGD("outputtmp %0x", outputtmp); memcpy(output+(6+i*4), &outputtmp, sizeof(int)); } for(int i=0; i<=0x25; i++){ LOGD("output %0x %0x", i, output[i]); } return 0; } void main(){ int tblen = strlen(keytb); const char* input = "pediy_imyang_lXcaTALmow"; char* output = new char[0x200]; keygen_13CE4(input, strlen(input), keytb_42210, tblen, output); }