这是一个很有趣的题目,在调试的时候密钥是随机变化的。

下载下来的文件没有加壳,直接拖入IDA分析,可以直接看到main函数

首先是4个4个字节的密钥,可以很像是TEA算法,但是还不确定,输入的flag是48字节,首先进入了一个函数,里面就是字节换序:

:::color1
*(_DWORD )(4LL * i + a2) = ((unsigned __int8 *)(4 * i + 2LL + s) << 16) | *(unsigned __int8 )(4 * i + 3LL + s) | ((unsigned __int8 )(4 * i + s) << 8) | ((unsigned __int8 *)(4 * i + 1LL + s) << 24);

:::

下面是对v8全部字节进行加密操作,rand_tea里面是把v6,v7全部改写了的,不是表面上v6变了,v7没变。进入rand_tea函数,可以观察到就是TEA加密的结构,但是是魔改后的:

然后就能发现一个关键的东西:rand函数,众所周知,rand是随机数函数,这个就….有点麻烦了,先暂时放着

回到main函数,之后又是一个recover_mass函数,里面其实也是字节变序的。

最后经过一系列的变换后,与enflag进行比较,相同就是flag。那么,我们的思路就是反过来,比较好解决的就是recover_massmake_mass,可以写出逆向函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void recover_mass_re(_DWORD* a1, unsigned char* a2) {
for (int i = 0; i != 12; ++i) {
a1[i] = a2[4 * i + 2];
BYTE1(a1[i]) = a2[4 * i + 3];
BYTE2(a1[i]) = a2[4 * i];
HIBYTE(a1[i]) = a2[4 * i + 1];
}
}
void make_mass_re(char* s, _DWORD* a2) {
for (int i = 0; i != 12; ++i) {
s[4 * i] = BYTE1(a2[i]);
s[4 * i + 1] = BYTE3(a2[i]);
s[4 * i + 2] = BYTE2(a2[i]);
s[4 * i + 3] = BYTE(a2[i]);
}
}

rand_tea其实也很好写出逆向函数,但是有随机数的存在,让 v7和 v5的值不确定。我们假设v7确定,就能求出v5,先写出逆向函数:

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
__int64 __fastcall rand_tea_re(unsigned int* data, _DWORD* key,uint32 v7) {
__int64 result; // rax
unsigned int v3; // [rsp+18h] [rbp-18h]
unsigned int v4; // [rsp+1Ch] [rbp-14h]
unsigned int v5; // [rsp+20h] [rbp-10h]
int i; // [rsp+24h] [rbp-Ch]

v3 = *data;
v4 = data[1];

v5 = 0xDEADBEEF;
for (int i = 0; i != 114; ++i) {
v5 += v7 * i;
}

for (i = 113; i >= 0; --i) {
v4 -= (v3 - v5) ^ key[1] ^ (v3 << ((char)(i + 2) % 6)) ^ (v3 >> ((int)(i + 3) % 7)) ^ key[3];
v3 -= (v4 - v5) ^ key[2] ^ (v4 << ((char)(i + 1) % 5)) ^ (v4 >> ((i + 4) & 7)) ^ *key;
v5 -= v7 * i;
}
*data = v3;
result = v4;
data[1] = v4;
return result;
}

我们进入rand函数进行分析:

里面是对rand_sand进行一系列的操作,我们查看rand_sand是从哪里来的

可惜是一个变量,不是常量,查看交叉引用,果然,出现了一个奇怪的函数:

rand_sand就是由它初始化的,我们查找这个函数的引用,欸,竟然是pthread_create

再查询该函数的引用,结果是init_array,函数会在程序进入main函数之前就执行

再看rand_sand,里面有一个sleep(1u),然后再对key进行变换,延迟枪哈,所以进入rand_tea进行加密的密钥并不是main里面的臭数字。我们看rand_sand里面的sub_40128A

里面有一个从 start函数到 main函数结束的代码字节遍历,下面是一个ptrace,还是trace_me

如果调试器附加,ptrace会返回-1,否则就是0。

总结一下:该程序自己有一个init_array块,里面创建了一个线程,并且对start到main函数字节码的遍历,然后再使用ptrace的值,构成了一个rand_sand,该线程休眠了1秒,这其中的一秒,main函数完成了对key的初始化,然后等待用户的输入。回到副线程,休眠过后,就对key进行异或操作,之后退出。用户输入flag后,进行字节码的换序,然后进入rand_tea加密,之后再进行一次乱序,最后和enflag进行比较。

上面是我做出来后的总结,其实过程并不是那么顺利,dancing keys为什么会dancing?问题就是出现在遍历字节码上。这个遍历把大部分函数都遍历了一遍。如果想要调试查看keys的值,就会发现keys一直在变换。原因就是调试器断点,特别是软件断点0xCC,修改了字节码,就会导致另外一个线程在遍历时,读取到了不同字节编码,导致rand_sand变化。ptrace也有反调试的效果,调试时会返回-1,非调试状态返回0。但是在这里修改是没有意义的,因为上面会遍历函数字节编码。 所以不能对程序里面的函数进行修改或者调试,我们可以把 从start 到 main的字节复制下来,自己进行一个变换,然后自己写一个rand_sand 和 rand函数,再来到main函数逆向。

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
int calc_sand() {
unsigned long long start[280] = {
0x8949ED31FA1E0FF3, 0xE48348E289485ED1, 0xC931C031455450F0, 0xFF00401760C7C748,
0x2E66F400002E8315, 0x0000000000841F0F, 0x0F2E66C3FA1E0FF3, 0x900000000000841F,
0x503D4800404050B8, 0x0000B81374004040, 0xBF0974C085480000, 0x9066E0FF00404050,
0x00841F0F2E6666C3, 0x00401F0F00000000, 0xEE814800404050BE, 0x48F0894800404050,
0x4803F8C1483FEEC1, 0xB81174FED148C601, 0x74C0854800000000, 0xE0FF00404050BF07,
0x00841F0F2E6666C3, 0x00401F0F00000000, 0x2E653D80FA1E0FF3, 0x8948551375000000,
0x05C6FFFFFF7AE8E5, 0x90C35D0100002E53, 0x00841F0F2E6666C3, 0x00401F0F00000000,
0x0FF38AEBFA1E0FF3, 0x058BE5894855FA1E, 0x890BE0C100002E3C, 0x3100002E31058BC2,
0x8B00002E290589D0, 0x04E8C100002E2305, 0x00002E18058BC289, 0x00002E100589D031,
0xE0C100002E0A058B, 0x002DFF058BC28905, 0x002DF70589D03100, 0xC100002DF1058B00,
0x2DE6058BC2890EE8, 0x2DDE0589D0310000, 0x00002DD8058B0000, 0x4855FA1E0FF3C35D,
0x894830EC8348E589, 0x45C7D0758948D87D, 0xE445C700000000E0, 0xD8458B4800000000,
0xE845C748F0458948, 0x8B4834EB00000000, 0x0148E8458B48F055, 0x48C0B60F00B60FD0,
0x4501C2AF0FE8558B, 0x458B48F0558B48E0, 0x0F00B60FD00148E8, 0x458348E44531C0B6,
0x3B48E8458B4801E8, 0x000000B9C272D045, 0x00BE00000000BA00, 0x00000000BF000000,
0xFDD6E800000000B8, 0x8B48F8458948FFFF, 0x45AF0FE44533F845, 0x55FA1E0FF3C3C9E0,
0x48E87D8948E58948, 0x45C7DC5589E07589, 0x008EE900000000FC, 0x02E0C1FC458B0000,
0x8B4803508D489848, 0x00B60FD00148E845, 0xE2C1FC558BC0B60F, 0xE8558B48CA634802,
0xB60F12B60FCA0148, 0x458BC20908E2C1D2, 0x8D48984802E0C1FC, 0x0148E8458B480248,
0xC1C0B60F00B60FC8, 0x458BC109D18910E0, 0x8D48984802E0C1FC, 0x0148E8458B480150,
0xC1C0B60F00B60FD0, 0x48FC458BC28918E0, 0x00000085348D4898, 0xF00148E0458B4800,
0x01FC45831089CA09, 0xC08503508DDC458B, 0x453902F8C1C2480F, 0x90FFFFFF5B8C0FFC,
0x55FA1E0FF3C35D90, 0x48E87D8948E58948, 0x45C7DC5589E07589, 0x00C4E900000000FC,
0x489848FC458B0000, 0x480000000085148D, 0x088BD00148E8458B, 0x984802E0C1FC458B,
0xE0458B4802508D48, 0x8B1088CA89D00148, 0x85148D489848FC45, 0xE8458B4800000000,
0x08E8C1008BD00148, 0x02E0C1FC458BC189, 0x8B4803508D489848, 0x88CA89D00148E045,
0x8D489848FC458B10, 0x8B48000000008514, 0xC1008BD00148E845, 0xC1FC458BC18910E8,
0x458B48D0634802E0, 0x1088CA89D00148E0, 0x148D489848FC458B, 0x458B480000000085,
0xE8C1008BD00148E8, 0xE0C1FC458BC18918, 0x4801508D48984802, 0xCA89D00148E0458B,
0x458B01FC45831088, 0xFF308C0FDC453BFC, 0x0FF3C35D9090FFFF, 0x8348E5894855FA1E,
0x8D48D87D894830EC, 0x458948FFFFFC3305, 0x000004E5058D48F0, 0x48FFFFFC21158D48,
0x8B48F8458948D029, 0x8948F0458B48F855, 0xFFFD61E8C78948D6, 0xBF00002B310589FF,
0xFFFBE7E800000001, 0x00000000EC45C7FF, 0xE800000000B841EB, 0x48EC558BFFFFFCCA,
0x0000950C8D48D263, 0x002B0F158D480000, 0xC189D03111148B00, 0x148D489848EC458B,
0x058D480000000085, 0x83020C8900002AF4, 0x7E03EC7D8301EC45, 0xC3C900000000B8B9,
0xE5894855FA1E0FF3, 0x048B486410EC8348, 0x4589480000002825, 0xB9F0458D48C031F8,
0x2B158D4800000000, 0x00000000BEFFFFFF, 0xFFFFFB38E8C78948, 0xE8C78948F0458B48,
0x458B4890FFFFFB0C, 0x002825042B4864F8, 0xFFFAE7E805740000, 0x55FA1E0FF3C3C9FF,
0x4830EC8348E58948, 0x48D0758948D87D89, 0xE84589008BD8458B, 0x8904408BD8458B48,
0xADBEEFF045C7EC45, 0xF3E800000000B8DE, 0x45C7F84589FFFFFB, 0xF445C700000072FC,
0x000102E900000000, 0xF845AF0FF4458B00, 0x488DF4458BF04501, 0x67C06948C1634801,
0x8920E8C148666666, 0x1FF8C1C889FAD1C2, 0x0102E0C1D089C229, 0xEC458BCA89C129D0,
0x8B48C289E0D3D189, 0x008B08C08348D045, 0xF0452BEC458BC231, 0x83F4458BC631D689,
0xEC558B07E08304C0, 0xD0458B48EAD3C189, 0x4501F031D031008B, 0x4802488DF4458BE8,
0xAAAAABC06948C163, 0xC2894820E8C1482A, 0x89C2291FF8C1C889, 0x29C001D001C001D0,
0xD189E8458BCA89C1, 0xD0458B48C289E0D3, 0xC231008B04C08348, 0xD689F0452BE8458B,
0x03C083F4458BC631, 0x2493D26948D06348, 0xC20120EAC1489249, 0x1FF9C1C18902FAC1,
0x2903E1C1D189CA29, 0xE8458BC289C829D1, 0x8B48C289E8D3D189, 0x008B0CC08348D045,
0x83EC4501F031D031, 0x453BF4458B01F445, 0x48FFFFFEF2820FFC, 0x1089E8558BD8458B,
0x04508D48D8458B48, 0xC3C9900289EC458B, 0xE5894855FA1E0FF3, 0x64000000C0EC8148,
0x0000002825048B48, 0x85C7C031F8458948, 0xFFFFFFFFFFFFFF48, 0x74FFFFFFFF48BD83,
0x00FFFFFF48BD8132, 0x48BD813974FFFF80, 0x77FFFF8000FFFFFF, 0x29FFFFFF48BD817B,
0x48BD815A74973A72, 0x74FFF98000FFFFFF, 0x0028A305C761EB38, 0x48A5C11234567800,
0x05C74EEB0FFFFFFF, 0x90ABCDEF00002894, 0xD089FFFFFF48958B, 0x0102E0C1D001C001,
0xEBFFFFFF488589D0, 0x190000287505C72B, 0xFFFF48B581114514, 0xC715EB68C3F229FF,
0x8101140000286305, 0x0CFFFFFF488D8119, 0xFF48BD81908D90E1, 0x05749FBAF32DFFFF,
0x8D4890FFFFFF53E9, 0xC789480000081305, 0x458D48FFFFF86BE8, 0x0F058D48C68948C0,
0x00B8C78948000008, 0xFFFFF8B0E8000000, 0xE8C78948C0458D48, 0xFF548589FFFFF854,
0xFFFFFF54BD83FFFF, 0x07E5058D48197430, 0xF826E8C789480000, 0xE90001BF52B8FFFF,
0x608D8D4800000133, 0xBAC0458D48FFFFFF, 0x48CE894800000030, 0xC7FFFFFA7CE8C789,
0x000000FFFFFF4C85, 0xFFFF4C858B7AEB00, 0xFF6085848B9848FF, 0xFFFFFF588589FFFF,
0xC083FFFFFF4C858B, 0xFF6085848B984801, 0xFFFFFF5C8589FFFF, 0x48FFFFFF58858D48,
0x89480000277A158D, 0xFFFCEAE8C78948D6, 0x8BFFFFFF58958BFF, 0x899848FFFFFF4C85,
0x858BFFFFFF608594, 0x8B01C083FFFFFF4C, 0x899848FFFFFF5C95, 0x8583FFFFFF608594,
0x4CBD8302FFFFFF4C, 0xFF798E0F0BFFFFFF, 0x8D48904D8D48FFFF, 0x000CBAFFFFFF6085,
0xC78948CE89480000, 0x5085C7FFFFFA96E8, 0xEB00000000FFFFFF, 0x48FFFFFF50858B41,
0x858B900554B60F98, 0x8D489848FFFFFF50, 0x04B60F0000069B0D, 0x058D481674C23808,
0xE8C78948000006E1, 0x01BF52B8FFFFF714, 0xFFFF50858324EB00, 0xFFFFFF50BD8301FF,
0x06C7058D48B67E2F, 0xF6EEE8C789480000, 0x48001D4B42B8FFFF, 0x25142B4864F8558B,
0xF5E8057400000028, 0x000000C3C9FFFFF6, 0x08EC8348FA1E0FF3, 0x000000C308C48348
};
int v3 = 0; int v4 = 0;
for (int i = 0; i != 0x8BD; ++i) {
v3+=i*((BYTE*)(start))[i];
v4 ^= ((BYTE*)(start))[i];
}
return v3 * (v4 ^ 0);
}

rand 函数直接照抄就行:

1
2
3
4
5
6
7
unsigned int t_rand() {
rand_sand ^= rand_sand << 11;
rand_sand ^= (unsigned int)rand_sand >> 4;
rand_sand ^= 0x20 * rand_sand;
rand_sand ^= (unsigned int)rand_sand >> 14;
return (unsigned int)rand_sand;
}

然后我们根据主函数的逻辑逆向就可以了:

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
int main() {
rand_sand = calc_sand();

uint32_t a1[12] = { 0 };
unsigned char buff[48];
unsigned char buff1[48];
recover_mass_re((_DWORD*)a1, enflag);

uint32_t key[4] = { 0x12345678, 0x90ABCDEF, 0x11451419, 0x19810114 };

for (int i = 0; i != 4; ++i) {
key[i] ^= t_rand();
}

rand_tea_re(&a1[0], key, t_rand());
rand_tea_re(&a1[2], key, t_rand());
rand_tea_re(&a1[4], key, t_rand());
rand_tea_re(&a1[6], key, t_rand());
rand_tea_re(&a1[8], key, t_rand());
rand_tea_re(&a1[10], key, t_rand());

make_mass_re((char*)buff1, a1);

return 0;
}

flag就是:flag{1_h4t3_h4sH_ch3cK1ng_4Nd_r4Nd0m_t3AenCRypt}