-
-
[原创]第八题 惊天阴谋 by k1ee
-
2020-12-7 20:46 5543
-
惊天阴谋
去花,修复各种干扰后,取得程序逻辑如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | const char * username = "141E8F96636898EF" ; const char * serial = "dd8c5dd5bff047cb86c51fc808254c0950ebd2d9c7e6b34679a6cda7f96ea0f46d105248c68b6534546d34c26534546d34c26534542538d289a28b2d14d06534546614d225146289a28b6614d249a7096d10522538d22538d289a28b48a21b2d14d041a69b2d14d06614d289a28b25146250a28948a21b48c68b48c68b49829948a21b6d105249a7092c345289a28b6534542c34522d14d050a2896d105225146289a28b6d105249a7092d14d049a7096d34c26d10522d14d049a70948a21b2d14d048c68b48a21b49a70925146248c68b41a69b08a69948c68b48c68b498299" ; uint8_t username_md5[ 16 ] = { 0 }; md5((uint8_t * )username, strlen(username), username_md5); uint8_t username_md5_1[ 16 ] = { 0 }; md5(username_md5, 8 , username_md5_1); uint8_t username_md5_2[ 16 ] = { 0 }; md5(username_md5 + 8 , 8 , username_md5_2); uint8_t serial_hex[ 224 ] = { 0 }; char * sp = (char * )serial; for ( int i = 0 ; i < 224 ; + + i) { sscanf_s(sp, "%2hhx" , &serial_hex[i]); sp + = 2 ; } uint8_t * serial_1 = serial_hex; uint8_t * serial_2 = serial_hex + 32 ; uint8_t result1_1[ 32 ] = { 0 }; uint32_t * pi = (uint32_t * )serial_1; uint32_t * po = (uint32_t * )result1_1; for ( int i = 0 ; i < 8 ; + + i) { * po + + = transform1_1( * pi + + ); } uint8_t result1_2[ 32 ] = { 0 }; memcpy(result1_2, result1_1, 32 ); HCRYPTPROV ctx; CryptAcquireContextA(&ctx, 0 , 0 , 24 , 0xF0000000 ); HCRYPTHASH hash ; CryptCreateHash(ctx, 0x800C , 0 , 0 , & hash ); unsigned char hashData[ 20 ] = { 0x31 , 0x5F , 0x4C , 0x30 , 0x56 , 0x33 , 0x5F , 0x42 , 0x58 , 0x53 , 0x5F , 0x46 , 0x30 , 0x52 , 0x45 , 0x56 , 0x45 , 0x52 , 0x21 , 0x00 }; CryptHashData( hash , hashData, 19 , 0 ); HCRYPTKEY key; CryptDeriveKey(ctx, 0x6610 , hash , 0 , &key); DWORD len = 32 ; CryptEncrypt(key, 0 , 0 , 0 , result1_2, & len , 32 ); uint8_t result1_2_trans[ 16 ] = { 0 }; for ( int i = 0 ; i < 16 ; + + i) { result1_2_trans[i] = result1_2[ 2 * i]; } transform1_2(result1_2_trans); / / Equals MD5 Part1 uint8_t result2_1[ 32 ] = { 0 }; transform2_1(serial_2, result2_1); uint8_t result2_2[ 16 ] = { 0 }; transform2_2(result2_1, result2_2); transform2_3(result2_2, username_md5_2); |
注册码分为两部分
1.3
魔改的AES,动调取得sbox,手算rsbox,解密。
1 2 3 4 5 6 7 8 9 10 11 12 | AES_ctx actx; int akey[ 8 ] = { 0 }; akey[ 0 ] = 0x59206F57 ; akey[ 1 ] = 0x59676E6F ; akey[ 2 ] = 0x206E6175 ; akey[ 3 ] = 0x75486958 ; akey[ 4 ] = 0x4B206E61 ; akey[ 5 ] = 0x75586E61 ; akey[ 6 ] = 0x754C206E ; akey[ 7 ] = 0x6E61546E ; AES_init_ctx(&actx, (uint8_t * )akey); AES_ECB_decrypt(&actx, username_md5_1); |
每一位+0x7F得到第二位
1 2 3 4 5 6 | uint8_t part1_1[ 32 ] = { 0 }; for ( int i = 0 ; i < 16 ; + + i) { part1_1[i * 2 ] = username_md5_1[i]; part1_1[i * 2 + 1 ] = username_md5_1[i] + 0x7F ; } |
1.2
调用API进行解密即可
1 2 3 4 5 6 7 8 9 10 | HCRYPTPROV ctx; CryptAcquireContextA(&ctx, 0 , 0 , 24 , 0xF0000000 ); HCRYPTHASH hash ; CryptCreateHash(ctx, 0x800C , 0 , 0 , & hash ); unsigned char hashData[ 20 ] = { 0x31 , 0x5F , 0x4C , 0x30 , 0x56 , 0x33 , 0x5F , 0x42 , 0x58 , 0x53 , 0x5F , 0x46 , 0x30 , 0x52 , 0x45 , 0x56 , 0x45 , 0x52 , 0x21 , 0x00 }; CryptHashData( hash , hashData, 19 , 0 ); HCRYPTKEY key; CryptDeriveKey(ctx, 0x6610 , hash , 0 , &key); DWORD len = 32 ; CryptDecrypt(key, 0 , 0 , 0 , part1_1, & len ); |
1.1
六种运算的虚拟机,把所有指令打出来,然后分析可以看出有很多重复的部分,懒得写程序提炼,于是手动提炼了一部分,12万行缩小到1.2万行,编译爆破程序求解,16线程106分钟解得所有逆向关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | uint32_t * ansbuf = new uint32_t[ 0x10000000 ]; for ( int i = 0 ; i < 16 ; + + i) { uint32_t val = i * 0x10000000 ; char filename[ 128 ] = { 0 }; sprintf_s(filename, "E:/Ctf/KCTF2020Q4/KCTF-KeyME/Solver/Solver/Release/%08X_%08X.bin" , val, val + 0xFFFFFFF ); FILE * fp; fopen_s(&fp, filename, "rb" ); int ret = fread(ansbuf, 4 , 0x10000000 , fp); fclose(fp); for ( int k = 0 ; k < 0x10000000 ; + + k) { uint32_t input = val + + ; uint32_t output = ansbuf[k]; for ( int t = 0 ; t < 8 ; + + t) { if (pi[t] = = output) { po[t] = input ; / / pos[t].push_back( input ); } } } } delete[] ansbuf; printf( "Serial Part 1\n" ); for ( int i = 0 ; i < 32 ; + + i) { printf( "%02x" , part1_2[i]); } |
1 | 83bde72e2806ce3c8f424e242559a66314bb37008d62a69bfd1a960f8e4102c8 |
2.3
一个可逆算法,直接算出输入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | int buf1[ 8 ] = { 0x18111C1A , 0x1190C08 , 0x10070B20 , 0x151D0217 , 0x12161B14 , 0xA1E05 , 0xD130309 , 0x1F0E0604 }; int buf2[ 8 ] = { 0x14161715 , 0x12040C13 , 0xE100603 , 0xF1C180A , 0x50B001F , 0x200D1A08 , 0x9111D1E , 0x1B010219 }; int buf3[ 8 ] = { 0x11ECEE03 , 0xC050E14 , 0x5F7ED03 , 0xE700F600 , 0xBEFE800 , 0xFF0403F5 , 0xF4061600 , 0xF90918EF }; uint8_t * p1 = (uint8_t * )buf1; uint8_t * p2 = (uint8_t * )buf2; uint8_t * p3 = (uint8_t * )buf3; uint8_t target_m[ 16 ] = { 0x15 , 0x09 , 0x0c , 0x1f , 0x1c , 0x13 , 0x16 , 0x19 , 0x1d , 0x03 , 0x10 , 0x0f , 0x01 , 0x02 , 0x1e , 0x06 }; for ( int i = 0 ; i < 16 ; + + i) { uint8_t mid = target_m[i] - p3[i] + md5c[i]; cal[i] = __ROL__(mid, p1[i] & 7 ) ^ p2[i]; } |
2.2
最令人头痛的算法,我记录了所有和输入有关的运算,发现还是可逆的,也就三处需要记录
每一处输入输出关系也就65423个,因此爆破即可,从后往前还原数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | uint16_t r2_r1(uint64_t res, uint64_t v3, uint64_t v2) { std::vector< int > ret; for ( int i = 65422 ; i > = 0 ; - - i) { if (res = = (i * (v3 * v3 % 65423 * v2 % 65423 ) % 65423 )) { ret.push_back(i); } } if (ret.size() ! = 1 ) { _CrtDbgBreak(); } return ret[ 0 ]; } uint16_t r2_r2(uint64_t res, uint64_t val, uint64_t bp) { std::vector< int > ret; for ( int i = 65422 ; i > = 0 ; - - i) { uint64_t r = ((int64_t)(i - val * bp) % 65423 + 65423 ) % 65423 ; if (res = = r) { ret.push_back(i); } } if (ret.size() ! = 1 ) { _CrtDbgBreak(); } return ret[ 0 ]; } uint16_t r2_r3(uint64_t res, uint64_t v1, uint64_t v2, uint64_t v3) { std::vector< int > ret; for ( int i = 65422 ; i > = 0 ; - - i) { uint64_t r = ((int64_t)(i * v1 - v2 * v3) % 65423 + 65423 ) % 65423 ; if (res = = r) { ret.push_back(i); } } if (ret.size() ! = 1 ) { _CrtDbgBreak(); } return ret[ 0 ]; } struct re2_op { int bufptr_res; int bufptr_another; uint64_t mul_val1; uint64_t min_val3; }; void reverse2_2(uint16_t * input , uint8_t * output) { uint8_t buf1[ 0x370 * 16 ] = { 0 }; int64_t * b1ptr1 = (int64_t * )buf1; int32_t * t1ptr = (int32_t * )table_trans2; for ( int i = 0 ; i < 16 ; + + i) { int64_t val1 = * t1ptr + + ; for ( int k = 15 ; k > = 0 ; - - k) { int64_t val2 = 0 ; if (k > 0 ) { int64_t val3 = transform2_calc1(val1, k >> 1 ); val2 = val3 * val3 % 65423 ; if (k & 1 ) val2 = val2 * val1 % 65423 ; } else { val2 = 1 ; } * b1ptr1 + + = val2; } b1ptr1 = (int64_t * )(buf1 + 0x370 * (i + 1 )); } for ( int i = 0 ; i < 16 ; + + i) { uint64_t * b1ptr2 = (uint64_t * )(buf1 + 0x80 + i * 0x370 ); * b1ptr2 = 0xDEAD ; } std::vector<re2_op> ops; uint64_t * b1ptr3 = (uint64_t * )buf1; for ( int i = 1 ; i < = 15 ; + + i) { uint64_t * b1ptr7 = (uint64_t * )(buf1 + 0x370 * i + 8 * (i - 1 )); for ( int a1 = 16 - i; a1 > = 1 ; - - a1) { uint64_t val3 = * b1ptr7; uint64_t * b1ptr8 = b1ptr3; uint64_t * b1ptr9 = b1ptr7; for ( int a2 = 18 - i; a2 > = 1 ; - - a2) { uintptr_t diff3 = ((uintptr_t)b1ptr3 - (uintptr_t)buf1); uintptr_t diff7 = ((uintptr_t)b1ptr7 - (uintptr_t)buf1); uintptr_t diff8 = ((uintptr_t)b1ptr8 - (uintptr_t)buf1); uintptr_t diff9 = ((uintptr_t)b1ptr9 - (uintptr_t)buf1); if (diff9 % 0x370 = = 0x80 ) { re2_op op; op.bufptr_res = diff9 / 0x370 ; op.bufptr_another = diff8 / 0x370 ; op.mul_val1 = * b1ptr3; op.min_val3 = val3; ops.push_back(op); } * b1ptr9 + + = ((int64_t)( * b1ptr9 * * b1ptr3 - val3 * * b1ptr8 + + ) % 65423 + 65423 ) % 65423 ; } b1ptr7 + = 110 ; } b1ptr3 + = 111 ; } uint16_t * op = (uint16_t * )output; uint64_t bufrec_1[ 16 ] = { 0 }; int64_t * b1p2 = (int64_t * )buf1; for ( int k = 0 ; k < 16 ; + + k) { int64_t v2 = * b1p2; int64_t v3 = transform2_calc1( * b1p2, 0x7FC6 ); uint16_t ret = r2_r1( input [k], v3, v2); for ( int t = 15 ; t > k; - - t) { ret = r2_r2(ret, input [t], * (uint64_t * )(buf1 + k * 0x370 + t * 8 )); } bufrec_1[k] = ret; b1p2 + = 111 ; } for ( int i = ops.size() - 1 ; i > = 0 ; - - i) { re2_op op = ops[i]; bufrec_1[op.bufptr_res] = r2_r3(bufrec_1[op.bufptr_res], op.mul_val1, op.min_val3, bufrec_1[op.bufptr_another]); } for ( int i = 0 ; i < 16 ; + + i) { op[i] = bufrec_1[i]; } } |
2.1
似乎是个矩阵,不过当时太累了,爆破也不是很难
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | bool reverse2_1(uint8_t * input , uint8_t * output) { uint8_t buf[ 0x200 ] = { 0 }; int8_t * kptr = (int8_t * )&buf[ 511 ]; int * tptr = ( int * )table_check2; uint8_t * iptr = input + 7 ; for ( int i = 0 ; i < 8 ; + + i) { for ( int p = 0 ; p < 8 ; + + p) { bool solved = false; int8_t sb_solved[ 8 ] = { 0 }; const int smax = 4 ; for ( int s1 = - 4 ; s1 < = smax; s1 + = 2 ) { for ( int s2 = - 4 ; s2 < = smax; s2 + = 2 ) { for ( int s3 = - 4 ; s3 < = smax; s3 + = 2 ) { for ( int s4 = - 4 ; s4 < = smax; s4 + = 2 ) { for ( int s5 = - 4 ; s5 < = smax; s5 + = 2 ) { for ( int s6 = - 4 ; s6 < = smax; s6 + = 2 ) { for ( int s7 = - 4 ; s7 < = smax; s7 + = 2 ) { for ( int s8 = - 4 ; s8 < = smax; s8 + = 2 ) { int8_t sb[ 8 ] = { s1, s2, s3, s4, s5, s6, s7, s8 }; int a1 = ((iptr[ 0 ] >> p) & 1 ) = = 1 ? 8 : - 8 ; int a2 = ((iptr[ 8 ] >> p) & 1 ) = = 1 ? 8 : - 8 ; int a3 = ((iptr[ 16 ] >> p) & 1 ) = = 1 ? 8 : - 8 ; int a4 = ((iptr[ 24 ] >> p) & 1 ) = = 1 ? 8 : - 8 ; for ( int k = 7 ; k > = 0 ; - - k) { int c = sb[k]; a1 - = c * tptr[ 24 + k]; a2 - = c * tptr[ 16 + k]; a3 - = c * tptr[ 8 + k]; a4 - = c * tptr[k]; } if (a1 = = 0 && a2 = = 0 && a3 = = 0 && a4 = = 0 ) { solved = true; memcpy(sb_solved, sb, 8 ); goto solved; } } } } } } } } } solved: if (!solved) return false; for ( int k = 7 ; k > = 0 ; - - k) { * kptr - - = sb_solved[k]; } } iptr - - ; } uint8_t * optr = output; int8_t * bptr = (int8_t * )buf; for ( int i = 0 ; i < 64 ; + + i) { for ( int k = 0 ; k < 8 ; + + k) { bptr[k] / = 2 ; bptr[k] + = 2 ; } optr[ 0 ] = (bptr[ 0 ] << 5 ) | (bptr[ 1 ] << 2 ) | (bptr[ 2 ] >> 1 ); optr[ 1 ] = (bptr[ 2 ] << 7 ) | (bptr[ 3 ] << 4 ) | (bptr[ 4 ] << 1 ) | (bptr[ 5 ] >> 2 ); optr[ 2 ] = (bptr[ 5 ] << 6 ) | (bptr[ 6 ] << 3 ) | (bptr[ 7 ]); optr + = 3 ; bptr + = 8 ; } return true; } |
此题应该多解,我没求出预期解
结束
1 | 83bde72e2806ce3c8f424e242559a66314bb37008d62a69bfd1a960f8e4102c81001040041040241004a20844a20840201040200000201040241001241041200040040000208041200040008000241001001040200000208040000041001040001244a20840041041001040201040208044a20840200000041040200004a20844a20840208040000040001240041040041040001240241000009040208040040000009040208040240044a20840000040240040009040041040201041200041001041200040241000041041200040008000208044a2084100104020804000100 |
杂记
https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
实际上是从KernelBase和advapi32里找函数
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
赞赏
看原图