分析过程
首先使用IDA打开,发现只有几个函数,应该是加壳了,但是使用PE工具,查不到壳信息,用010editor 打开,发现4.02,应该是UPX的壳,但是特征被改了,所以导致无法脱壳,修改回UPX后,使用upx-d,成功脱壳。
再次使用IDA打开,入口有个V函数,进去看下
这里V的返回值是没有使用过的,所以直接改成void,这里有两个数组,一个auth,一个memstore
这里的操作都是对V3进行操作,也就是auth数组的操作,那我们不关心内部的具体实现,直接动态把auth数组dump出来,这里有个反调试,ptrace直接nop掉,传到手机上,IDA附加,main里面打个断点,把处理过的auth数字打印出来
auth=[0x0003B148, 0x000D2CAE, 0x0003A1FB, 0x00044F40, 0x000472DE, 0x0000CCC0, 0x00001888, 0x00003B80, 0x000702F7, 0x000C745C, 0x000658E0, 0x000858D4, 0x0000D5BD, 0x00004860, 0x0014F410, 0x0002CB9F, 0x000321DB, 0x0014D534, 0x00025DA0, 0x0006898C, 0x00123D56, 0x00058E4D, 0x00050CF8, 0x00005D64, 0x000978BA, 0x0008F290, 0x0003B568, 0x00054696, 0x00094C12, 0x0001021F, 0x000DBACB, 0x00049680, 0x0002FABD, 0x000F2B58, 0x0012D23C, 0x0014AED3]
这里进行了一堆操作,也看不懂,也没有什么输出,就动态一直调呗,调试的时候看下内存中自己输入的值,大概就是对格式的校验,需要SYC{}的格式才会走到后面的计算函数,
进入p函数,这里IDA的识别有点问题,修正一下V8数组,更好看
这里有两部分的操作,第一部分的关键操作:
v3 = ((unsigned __int8)v8[v1] >> 4) | (16 * (unsigned __int8)v8[v1]);
v8[v1] = ((unsigned __int8)v8[v1] >> 4) | (16 * v8[v1]);
v8[v1++] = v2[strlen(v8)] ^ v3;
在这里,一开始不是很懂,在这里v8[v1] >> 4,就是右移四位,如果 v8[v1] 为 1100 1010,那么右移 4 位后的结果为 0000 1100,(16 * (unsigned __int8)v8[v1])是左移四位,在二进制数中,乘以 2 的幂(如 2、4、8、16 等)相当于将数的二进制位向左移动。这是因为在二进制数中,每位的权重是 2 的幂。
以乘以 16 为例,16 等于 2 的 4 次方(2^4 = 16),所以乘以 16 相当于将二进制位向左移动 4 位。然后再按位或,就完成了高低四位的交换,那后续逆向算法再交换一次就回来了,v8[v1++] = v2[strlen(v8)] ^ v3;就是将高低四位交换后的值和输入flag的最后一个元素异或,结果存到V8,那么这部分的逆向算法,就是先将数组的最后一位和第一位异或,然后高低四位交换
for i in range(36):
auth[36-i-1]^=auth[i]
#(auth[36-i-1]&0xF0 )>> 4) |((auth[36-i-1]&0xF )<<4)是完成高低四位的交换
auth[36-i-1]=((auth[36-i-1]&0xF0 )>> 4) |((auth[36-i-1]&0xF )<<4)&0xFF
第二部分,
for ( i = &memStore[18];
(_QWORD)*(i - 18) * (unsigned __int8)v8[v4] == *(v5 - 3)
&& (_QWORD)*(i - 12) * (unsigned __int8)v8[v4 + 1] == *(v5 - 2)
&& (_QWORD)*(i - 6) * (unsigned __int8)v8[v4 + 2] == *(v5 - 1)
&& (_QWORD)*i * (unsigned __int8)v8[v4 + 3] == *v5
&& (_QWORD)i[6] * (unsigned __int8)v8[v4 + 4] == v5[1]
&& (_QWORD)i[12] * (unsigned __int8)v8[v4 + 5] == v5[2];
++i )
从memstore数组,0,6,18位的元素乘以V8的0,1,2要和V5(处理过的auth数组)0,1,2相等,那逆向除一下就行了
for i in range(6):
for j in range(6):
auth[6*i+j]=auth[6*i+j]//memostore[j*6+i]
整个代码
auth=[0x0003B148, 0x000D2CAE, 0x0003A1FB, 0x00044F40, 0x000472DE, 0x0000CCC0, 0x00001888, 0x00003B80, 0x000702F7, 0x000C745C, 0x000658E0, 0x000858D4, 0x0000D5BD, 0x00004860, 0x0014F410, 0x0002CB9F, 0x000321DB, 0x0014D534, 0x00025DA0, 0x0006898C, 0x00123D56, 0x00058E4D, 0x00050CF8, 0x00005D64, 0x000978BA, 0x0008F290, 0x0003B568, 0x00054696, 0x00094C12, 0x0001021F, 0x000DBACB, 0x00049680, 0x0002FABD, 0x000F2B58, 0x0012D23C, 0x0014AED3]
memostore=[0x0000000000000D21, 0x000000000000009D, 0x000000000000094B, 0x00000000000003C9, 0x0000000000000C3F, 0x00000000000017E9, 0x000000000000130E, 0x0000000000000088, 0x0000000000000486, 0x000000000000202F, 0x0000000000002230, 0x00000000000024B4, 0x00000000000008B1, 0x0000000000000A9F, 0x0000000000001AD2, 0x00000000000023EB, 0x0000000000000C7E, 0x000000000000042B, 0x00000000000005BF, 0x000000000000113C, 0x0000000000000449, 0x0000000000001751, 0x0000000000000ACE, 0x0000000000001894, 0x000000000000208A, 0x0000000000000E82, 0x00000000000006BD, 0x0000000000000CEE, 0x0000000000002386, 0x00000000000013D4, 0x0000000000000111, 0x0000000000000D1C, 0x000000000000238E, 0x0000000000001759, 0x000000000000012B, 0x000000000000214D]
flag=''
for i in range(6):
for j in range(6):
auth[6*i+j]=auth[6*i+j]//memostore[j*6+i]
for i in range(36):
auth[36-i-1]^=auth[i]
#(auth[36-i-1]&0xF0 )>> 4) |((auth[36-i-1]&0xF )<<4)是完成高低四位的交换
auth[36-i-1]=((auth[36-i-1]&0xF0 )>> 4) |((auth[36-i-1]&0xF )<<4)&0xFF
for i in auth:
flag+=chr(i)
print(flag)