0x00 题目分析

8线程+1进程+反调试+多重加密+SMC

难度:easy

……

0x01 解

照例,查壳(Not packed)

没壳就拖进IDA直接到main函数看

多个线程+长度限制

还有看到个提权:https://www.jianshu.com/p/232fbd1a3cfb

感觉挺麻烦的

接下来看看每个线程都执行了什么函数

StartAddress函数

这个函数里面有个CreateProcessA,创建了一个进程,估计有一部分的操作是在创建的子进程里面进行的

sub_402460

下面有这个

这个byte_404210有点怪,里面是空的

sub_402630

这里面有个sub_401120

base64

结合这个base64和上面那个函数的1.37+1,可以知道上面那个函数应该是base58

参考:https://blog.csdn.net/weixin_34258782/article/details/88830132

sub_4020B0

看不太懂,但是应该是什么算法,下面有很多操作

结合WP,这应该是一个反调试(

反调试动态读取.text(第一个段)并通过累加的方式,不断读取对比的方式,来实现反调试。如果程序一开始就存在断点,则该反调试无效,若在调试中突然增加int3断点,则该程序直接退出

sub_401700

这些应该就是密文了,往下滑滑可以看到老朋友TEA

但是这个和原版不太一样,是XTEA

sub_4023A0

里面的这个sub_4012B0是这样的

看来是个base32的操作

sub_401E60

看不太懂,但是这个byte_406018有一大堆乱码,合理怀疑是被加密的什么东西

sub_4018F0

结合WP,这应该就是

上动调,会发现一下断点或者下了断点运行后程序会自动退出

看来有反调试,先干一下

刚刚那些进程里面的函数基本都有调用这个sub_4015E0

进这个函数看看

Dr7,看来这个是反调试了

参考:http://www.jybase.net/ruanjianpojie/20111221725.html

ExitProcess这个地方nop掉应该就行了

别忘了还要处理sub_4020B0

搞完之后就可以正常下断点调试了

看了一下官方WP发现有一个子线程是进行判断的,如果判断不对会直接退出程序

行吧,那就只能从上面的加密下手了

结合CreateProcessA和byte_406018的长度可以知道

这里应该是用了SMC

参考:https://segmentfault.com/a/1190000043519957

所以这串代码就要解密了

现在有两个方法进行解密

第一种是直接dump这段byte然后根据算法解密

第二种是直接动调然后在内存中找

第一种要注意解密顺序

可以根据各函数开头的while(dword_409804)来看,同时也要结合dword_409804来判断下一个执行的解密函数

以sub_401E60为例

这个算法是RC4,key是”MessageBoxA”(很有迷惑性)

它是第一个进行的解密,因为它的while (dword_409804 != 1)

它的下一个解密流程是dword_409804为3的函数

其他函数同理,顺序应该是

RC4 → Base32 → Base58 → Base64

解出结果是这样的

第二种方法就是直接动调然后在内存里找到解密后的代码

在CreateProcessA处下断点

之后在主线程中的WaitForMultipleObjects后会断下来

然后找到CreateProcessA下面的SetThreadContext

上图注意内存窗口的地址和ECX的值

然后就可以dump出来分析了

直接上IDA吧

函数很少,有用的就那么两个

主要是sub_2B2

往下滑滑,老朋友XTEA了

这里有点坑,数组长度要看v11,是4*i=64=0x40

看看这个函数的交叉引用

看来这个函数操作之后是用了MapViewOfFile传递给主函数的

然后就可以写脚本了

XTEA的抄抄大哥的

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
#include <iostream>

int main() {
int v12[16];
v12[0] = 0x88AFD2D6;
v12[1] = 0x3FBE45A7;
v12[2] = 0x27AAD1B9;
v12[3] = 0x8CB3E51E;
v12[4] = 0x9348FFA;
v12[5] = 0xE19F3C42;
v12[6] = 0xFFDD0D86;
v12[7] = 0xEDB97383;
v12[8] = 0x12C4C0BF;
v12[9] = 0x1B67BD19;
v12[10] = 0xF7A514D6;
v12[11] = 0x18F95254;
v12[12] = 0xAB100CB0;
v12[13] = 0xCBA137;
v12[14] = 0x2A91712;
v12[15] = 0xC58D0D9E;
int idx = 0;
do
{
unsigned int m0 = v12[2 * idx];
int sum = (-0x61C88647)*32;
unsigned int m1 = v12[2 * idx + 1];
int round = 32;
do
{
m1 -= (sum + m0) ^ (16 * m0 + 3) ^ ((m0 >> 5) + 4);
m0 -= (sum + m1) ^ (16 * m1 + 1) ^ ((m1 >> 5) + 2);
sum += 0x61C88647;
--round;
}
while ( round );
v12[2*idx] = m0;
v12[2*idx+1] = m1;
idx+=1;
}
while ( idx < 8 );
for(int i =0;i<16;i++){
int n = v12[i];
for(int j = 0;j<4;j++){
printf("%02X",(n>>(8*j))&0xff);
}
}
// 4E65704354467B633963646E77646933697534316D3070763378376B6C6C7A7538706471366D74396E326E776A6470366B617438656E743464686E3572313538
printf("\n========================================\n");


unsigned char vv[]={0x89,0x49,0x0C7,0x1D,0x77,0x0AF,0x79,0x0D9,0x6D,0x13,0x8D,0x88,0x7F,0x0DB,0x26,0x8E,0x0C9,0x3C,0x0C,0x0C1,0x40,0x5D,0x84,0x0C3,0x59,0x44,0x0E0,0x0C6,0x7,0x0DF,0x0EB,0x0A2,0x8D,0x38,0x84,0x0D4,0x0A2,0x56,0x0F9,0x12,0x59,0x0EE,0x0D7,0x5E,0x85,0x7F,0x13,0x43,0x0F0,0x0F9,0x43,0x0EF,0x0AA,0x83,0x96,0x0B2,0x0B4,0x40,0x36,0x8E,0x77,0x61,0x0D3,0x0C2};
int *v = (int*)vv;
int key[4];
key[0] = 18;
key[1] = 52;
key[2] = 86;
key[3] = 120;
for (int j = 0; j < 8; ++j )
{
unsigned int m0 = v[2 * j];
unsigned int m1 = v[2 * j + 1];
int sum = (-0x61C88647)*32;
for (int k = 0; k < 0x20; ++k )
{
m1 -= (key[3] + (m0 >> 5)) ^ (sum + m0) ^ (key[2] + 16 * m0);
m0 -= (key[1] + (m1 >> 5)) ^ (m1 + sum) ^ (key[0] + 16 * m1);
sum += 0x61C88647;

}
v[2 * j] = m0;
v[2 * j + 1] = m1;
}
for(int i =0;i<16;i++){
int n = v[i];
for(int j = 0;j<4;j++){
printf("%02X",(n>>(8*j))&0xff);
}
}

// 697534316D3070763378376B6C6C7A7538706471366D74396E326E776A6470366B617438656E743464686E3572313538697A326630636D72307537797879717D


return 0;
}

python转换自己写写了(

1
2
3
4
5
6
c1 = bytes.fromhex("4E65704354467B633963646E77646933697534316D3070763378376B6C6C7A7538706471366D74396E326E776A6470366B617438656E743464686E3572313538")
c2 = bytes.fromhex("697534316D3070763378376B6C6C7A7538706471366D74396E326E776A6470366B617438656E743464686E3572313538697A326630636D72307537797879717D")
# c2仅有后16字节与c1不同,取的时候记得去掉前面的
print(c1 + c2[-16:])

# b'NepCTF{c9cdnwdi3iu41m0pv3x7kllzu8pdq6mt9n2nwjdp6kat8ent4dhn5r158iz2f0cmr0u7yxyq}'