r3loads

直接看加密函数sub_1630。

在ida中通过动调,进入到运算函数中,给加密函数中涉及到对输入字符进行操作的操作符下条件断点,打印操作,这样的操作大概有好几种。

当然也可以用capstone之类的看汇编理解。

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
pow: 乘方
import ida_dbg
a = ida_dbg.get_reg_val("edi")
b = ida_dbg.get_reg_val("esi")
print(f"{hex(a)} ** {hex(b)} == {hex((a**b) &0xffffffff)}")

equl_add: 加等于
import ida_dbg
a = ida_dbg.get_reg_val("edx")
b = ida_dbg.get_reg_val("esi")
print(f"{hex(a)} += {hex(b)} == {hex((a+b) &0xffffffff)}")
#print(f"{hex(b)}, ",end='')

not: 取反
import ida_dbg
a = ida_dbg.get_reg_val("eax")
print(f"~{hex(a)} == {hex((~a) &0xffffffff)}")

box: 取值
import ida_dbg
a = ida_dbg.get_reg_val("rax")
b = ida_dbg.get_reg_val("esi")
addr = (a+((b<<2)&0xffffffff)) &0xffffffffffffffff
boxdata = ida_bytes.get_dword(addr)
print(f"*({hex(a)} + ({hex(b)} << 2)) == {hex(boxdata)}")

or: 或
import ida_dbg
a = ida_dbg.get_reg_val("edi")
b = ida_dbg.get_reg_val("esi")
print(f"{hex(a)} | {hex(b)} == {hex((a|b) &0xffffffff)}")

add: 加
import ida_dbg
a = ida_dbg.get_reg_val("edi")
b = ida_dbg.get_reg_val("esi")
print(f"{hex(a)} + {hex(b)} == {hex((a+b) &0xffffffff)}")

and: 与
import ida_dbg
a = ida_dbg.get_reg_val("edi")
b = ida_dbg.get_reg_val("esi")
print(f"{hex(a)} & {hex(b)} == {hex((a&b) &0xffffffff)}")

div: 除
import ida_dbg
a = ida_dbg.get_reg_val("rdi")
b = ida_dbg.get_reg_val("rsi")
print(f"{hex(a)} / {hex(b)} == {hex((a//b) &0xffffffff)}")

mul: 乘
import ida_dbg
a = ida_dbg.get_reg_val("edi")
b = ida_dbg.get_reg_val("esi")
print(f"{hex(a)} * {hex(b)} == {hex((a*b) &0xffffffff)}")

xor: 异或
import ida_dbg
a = ida_dbg.get_reg_val("edi")
b = ida_dbg.get_reg_val("esi")
print(f"{hex(a)} ^ {hex(b)} == {hex((a^b)&0xffffffff)}")

为了看清的方便调试,也可以动调把函数全部重命名。

打印全部操作

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
159
160
161
162
163
164
165
166
167
168
bufl = 0x64636261  bufr = 0x68676665 

0x0 & 0x3 == 0x0
0xe738364f + 0x4db280ef == 0x34eab73e
0x71dacd7 | 0xc09a2b7c == 0xc79fafff
0x59a346e2 & 0x3a59d43d == 0x18014420
0x2d65ec8d * 0xb56e09ec == 0xc4dd06fc
0xc6b3c818 ^ 0x80055085 == 0x46b6989d
0xf6d37e0b + 0x3de82e3d == 0x34bbac48
0xa02024b1 + 0xe68a261e == 0x86aa4acf
0xc24ec071 ^ 0x6c7d3339 == 0xae33f348
~0xae15c1b4 == 0x51ea3e4b
0xa03e720e ^ 0xe9ee0919 == 0x49d07b17
0x2aa09b28 ^ 0xfa8a8047 == 0xd02a1b6f
0xc87308ab & 0x744d58ab == 0x404108ab
0x91e55a57 * 0xfc368e81 == 0x6f08c7d7
0x6f08c7d7 | 0x404108ab == 0x6f49cfff
0x6f49cfff * 0x49d07b17 == 0x2cc134e9
0x2cc134e9 ^ 0xae33f348 == 0x82f2c7a1
0x82f2c7a1 * 0x34bbac48 == 0x79035148
~0x79035148 == 0x86fcaeb7
0x86fcaeb7 & 0xc79fafff == 0x869caeb7
0xe738364f + 0x4db280ef == 0x34eab73e
0x71dacd7 | 0xc09a2b7c == 0xc79fafff
0x59a346e2 & 0x3a59d43d == 0x18014420
0x2d65ec8d * 0xb56e09ec == 0xc4dd06fc
0xc6b3c818 ^ 0x80055085 == 0x46b6989d
0xf6d37e0b + 0x3de82e3d == 0x34bbac48
0xa02024b1 + 0xe68a261e == 0x86aa4acf
0xc24ec071 ^ 0x6c7d3339 == 0xae33f348
~0xae15c1b4 == 0x51ea3e4b
0xa03e720e ^ 0xe9ee0919 == 0x49d07b17
0x2aa09b28 ^ 0xfa8a8047 == 0xd02a1b6f
0xc87308ab & 0x744d58ab == 0x404108ab
0x91e55a57 * 0xfc368e81 == 0x6f08c7d7
0x6f08c7d7 | 0x404108ab == 0x6f49cfff
0x6f49cfff * 0x49d07b17 == 0x2cc134e9
0x2cc134e9 ^ 0xae33f348 == 0x82f2c7a1
0x82f2c7a1 * 0x34bbac48 == 0x79035148
~0x79035148 == 0x86fcaeb7
0x86fcaeb7 & 0xc79fafff == 0x869caeb7
0x869caeb7 / 0x7 == 0x133af463
0x133af463 * 0x7 == 0x869caeb5
0x2 ** 0x3 == 0x8
0x68676665 * 0x8 == 0x433b3328 ; bufr << 3
0xf806c191 | 0x357f1842 == 0xfd7fd9d3
0x82b97bbf | 0x48ea9c2e == 0xcafbffbf
~0x6c5c3899 == 0x93a3c766
~0x3f921364 == 0xc06dec9b
0xac507667 * 0x520c4bee == 0x505240c2
0x537759c1 & 0x42384d31 == 0x42304901
0x816ad1fb & 0x8b43c7f == 0x20107b
0x6a6ea4a3 + 0x58bc5155 == 0xc32af5f8
0x971c993e * 0x9fc7adf == 0x49f90902
0x49f90902 & 0xc32af5f8 == 0x41280100
0x41280100 & 0x42304901 == 0x40200100
0x40200100 | 0xc06dec9b == 0xc06ded9b
~0xc06ded9b == 0x3f921264
0xf806c191 | 0x357f1842 == 0xfd7fd9d3
0x82b97bbf | 0x48ea9c2e == 0xcafbffbf
~0x6c5c3899 == 0x93a3c766
~0x3f921364 == 0xc06dec9b
0xac507667 * 0x520c4bee == 0x505240c2
0x537759c1 & 0x42384d31 == 0x42304901
0x816ad1fb & 0x8b43c7f == 0x20107b
0x6a6ea4a3 + 0x58bc5155 == 0xc32af5f8
0x971c993e * 0x9fc7adf == 0x49f90902
0x49f90902 & 0xc32af5f8 == 0x41280100
0x41280100 & 0x42304901 == 0x40200100
0x40200100 | 0xc06dec9b == 0xc06ded9b
~0xc06ded9b == 0x3f921264
0x3f921264 / 0x7 == 0x914de0e
0x914de0e * 0x7 == 0x3f921262
0x2 ** 0x3 == 0x8
0x68676665 / 0x8 == 0xd0ceccc ; bufr >> 3
7FFFF7F37000: loaded /home/huanghunr/game/1/RRRRRRRRRRRRRRRRRRR3RR3RR333R3R3.so
7FFFF7F32000: loaded /home/huanghunr/game/1/RRRRRRRRRRRRRRRRRRR3RR3RR333R333.so
7FFFF7F2D000: loaded /home/huanghunr/game/1/RRRRRRRRRRRRRRRRRRR3RR3RR3333RR3.so
*(0x7fffffffcd50 + (0x0 << 2)) == 0xae ;sbox[0]
0xae + 0x0 == 0xae ;sbox[] +sum
0x433b3328 ^ 0xd0ceccc == 0x4e37dfe4 ;((bufr <<3) ^ (bufr >>3))
0x4e37dfe4 + 0x68676665 == 0xb69f4649 ;((bufr <<3) ^ (bufr >>3)) +bufr
~0xae == 0xffffff51 ;~(sbox[] + sum)
0xffffff51 & 0xb69f4649 == 0xb69f4641 ;~(sbox[] + sum) & 0xb69f4649
~0xb69f4649 == 0x4960b9b6
0x4960b9b6 & 0xae == 0xa6 ;(sbox[] + sum) & (~0xb69f4649)
0xa6 | 0xb69f4641 == 0xb69f46e7 ;a ^ b (a ^ b == (~a & b) | (a & ~b))
7FFFF7F28000: loaded /home/huanghunr/game/1/RRRRRRRRRRRRRRRRRRRR33333RRRR3R3.so
0x64636261 += 0xb69f46e7 == 0x1b02a948
0x33607b55 | 0xde4cad13 == 0xff6cff57
0x3c8c0c29 | 0xac64ce6a == 0xbcecce6b
~0x82e95826 == 0x7d16a7d9
~0xfe7c8c50 == 0x18373af
0xeb28aa82 * 0x7eae9b59 == 0x40bbfd32
0xde6bf394 ^ 0xd8050cf == 0xd3eba35b
0x88f767a6 | 0x6ef9c61c == 0xeeffe7be
0x83ff169b ^ 0xfe4cd3ff == 0x7db3c564
0xfdcb82ad ^ 0x3950fe46 == 0xc49b7ceb
0xfee6b1d1 + 0x1e967492 == 0x1d7d2663
0xa09a1807 + 0xa551f72c == 0x45ec0f33
0x45ec0f33 + 0x1d7d2663 == 0x63693596
0x63693596 + 0x7db3c564 == 0xe11cfafa
0xe11cfafa * 0xd3eba35b == 0xea9864de
0xea9864de & 0x18373af == 0x80608e
0x80608e & 0xbcecce6b == 0x80400a
0x33607b55 | 0xde4cad13 == 0xff6cff57
0x3c8c0c29 | 0xac64ce6a == 0xbcecce6b
~0x82e95826 == 0x7d16a7d9
~0xfe7c8c50 == 0x18373af
0xeb28aa82 * 0x7eae9b59 == 0x40bbfd32
0xde6bf394 ^ 0xd8050cf == 0xd3eba35b
0x88f767a6 | 0x6ef9c61c == 0xeeffe7be
0x83ff169b ^ 0xfe4cd3ff == 0x7db3c564
0xfdcb82ad ^ 0x3950fe46 == 0xc49b7ceb
0xfee6b1d1 + 0x1e967492 == 0x1d7d2663
0xa09a1807 + 0xa551f72c == 0x45ec0f33
0x45ec0f33 + 0x1d7d2663 == 0x63693596
0x63693596 + 0x7db3c564 == 0xe11cfafa
0xe11cfafa * 0xd3eba35b == 0xea9864de
0xea9864de & 0x18373af == 0x80608e
0x80608e & 0xbcecce6b == 0x80400a
0x80400a / 0x7 == 0x12524a
0x12524a * 0x7 == 0x804006
0x2 ** 0x5 == 0x20
0x1b02a948 / 0x20 == 0xd8154a ;>> 5
0x2c9c83e8 * 0x8e2a4ab9 == 0xcf4c62a8
0x32154ef1 * 0x367d350a == 0xbfd9fa6a
0xf4af1c08 | 0x19860d10 == 0xfdaf1d18
0x3e976f8f + 0x647f8454 == 0xa316f3e3
0xe009d4eb + 0x9c80e391 == 0x7c8ab87c
0xe6751635 + 0x25da6ba == 0xe8d2bcef
0x7753f9d2 * 0x41aeaeea == 0x454b15f4
0xc9e86bbd ^ 0x8b228ee8 == 0x42cae555
0xa855f008 & 0xc4e22ab0 == 0x80402000
0x80402000 | 0x42cae555 == 0xc2cae555
0xc2cae555 * 0xe8d2bcef == 0x390865b
0x390865b + 0xa316f3e3 == 0xa6a77a3e
~0xa6a77a3e == 0x595885c1
0x2c9c83e8 * 0x8e2a4ab9 == 0xcf4c62a8
0x32154ef1 * 0x367d350a == 0xbfd9fa6a
0xf4af1c08 | 0x19860d10 == 0xfdaf1d18
0x3e976f8f + 0x647f8454 == 0xa316f3e3
0xe009d4eb + 0x9c80e391 == 0x7c8ab87c
0xe6751635 + 0x25da6ba == 0xe8d2bcef
0x7753f9d2 * 0x41aeaeea == 0x454b15f4
0xc9e86bbd ^ 0x8b228ee8 == 0x42cae555
0xa855f008 & 0xc4e22ab0 == 0x80402000
0x80402000 | 0x42cae555 == 0xc2cae555
0xc2cae555 * 0xe8d2bcef == 0x390865b
0x390865b + 0xa316f3e3 == 0xa6a77a3e
~0xa6a77a3e == 0x595885c1
0x595885c1 / 0x7 == 0xcc380d2
0xcc380d2 * 0x7 == 0x595885be
0x2 ** 0x4 == 0x10 ;bufl <<4
0x1b02a948 * 0x10 == 0xb02a9480
~0xd8154a == 0xff27eab5
0xff27eab5 & 0xb02a9480 == 0xb0228080
~0xb02a9480 == 0x4fd56b7f
0x4fd56b7f & 0xd8154a == 0xd0014a
0xd0014a | 0xb0228080 == 0xb0f281ca
0x0 += 0xc3c67cdc == 0xc3c67cdc ; sum+=delta
0xb0f281ca + 0x1b02a948 == 0xcbf52b12
0xc3c67cdc / 0x800 == 0x1878cf ;>>11
0xff & 0x1878cf == 0xcf
*(0x7fffffffcd50 + (0xcf << 2)) == 0xbb
0xbb + 0xc3c67cdc == 0xc3c67d97 sbox[] + sum
0xcbf52b12 ^ 0xc3c67d97 == 0x8335685
0x68676665 += 0x8335685 == 0x709abcea

上面的步骤把加密过程复杂化了。

比如把异或运算进行了展开:a ^ b == (~a & b) | (a & ~b);

把左右位移替换成了对2的n次方的乘法和除法。

第一个文件的加密方式:xtea + rc4 的流密钥

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

using namespace std;

vector<uint8_t> sbox = {0xAE, 0x6F, 0xD5, 0xC9, 0xA0, 0x44, 0xB1, 0x95, 0x87, 0x21, 0x65, 0x8B, 0x74, 0x39, 0xA6, 0x84, 0x71, 0x31, 0x5E, 0x93, 0x77, 0xE0, 0xD0, 0x82, 0xBE, 0x3E, 0x1F, 0xC8, 0xC1, 0x67, 0x5C, 0xF9, 0xF6, 0x90, 0x89, 0x2A, 0xB6, 0xE1, 0xDE, 0x83, 0x88, 0x19, 0x3C, 0xC2, 0xE7, 0x1A, 0x4, 0x29, 0x4F, 0x27, 0x2F, 0xCB, 0x5D, 0x7F, 0xBA, 0x64, 0x49, 0x43, 0x30, 0x12, 0x41, 0xDB, 0x33, 0x10, 0x55, 0x3B, 0x35, 0x53, 0x40, 0x3D, 0xFF, 0x2, 0x9C, 0x51, 0x97, 0x5B, 0x22, 0x15, 0xB, 0x58, 0x4D, 0xB3, 0xEA, 0xC, 0x5A, 0xBF, 0xEE, 0xC6, 0xDF, 0xB7, 0x52, 0x60, 0xF8, 0xDC, 0x69, 0x1E, 0x6E, 0x14, 0x91, 0xA3, 0x98, 0x7C, 0xFC, 0x8, 0xCC, 0x7A, 0x46, 0x50, 0xC3, 0xB0, 0x68, 0x76, 0x9E, 0xCE, 0x62, 0x4A, 0xE4, 0x61, 0x2D, 0xE2, 0xD1, 0x4E, 0x85, 0x1B, 0x16, 0x6B, 0x79, 0x9, 0x94, 0x8F, 0xE8, 0x47, 0x7E, 0x81, 0x9D, 0x17, 0x80, 0x11, 0xC5, 0xD8, 0xF, 0x24, 0x96, 0xB2, 0x7, 0xED, 0xCA, 0xEC, 0x25, 0xA2, 0x3, 0xB5, 0x4C, 0xCF, 0x4B, 0xAA, 0xD4, 0xA8, 0xF2, 0x56, 0x9B, 0xAF, 0x57, 0x6C, 0xB8, 0x66, 0xF0, 0x7D, 0xAB, 0xD7, 0x34, 0xBC, 0x32, 0x59, 0x78, 0xD6, 0xC4, 0x1D, 0x99, 0xC0, 0x1, 0xEF, 0x92, 0x75, 0x2C, 0x63, 0x8A, 0xE, 0x38, 0x8D, 0x18, 0x6A, 0xE5, 0x2E, 0x26, 0x8E, 0x3F, 0xA1, 0xA5, 0x20, 0xF4, 0xFE, 0x1C, 0x42, 0xCD, 0xD2, 0x28, 0xBB, 0xD9, 0xA4, 0xEB, 0x9A, 0xC7, 0xA, 0xA9, 0x37, 0x8C, 0x5, 0xF3, 0x2B, 0x45, 0xDD, 0xFB, 0xAD, 0x6, 0xA7, 0x54, 0xD, 0x23, 0xB4, 0xF7, 0x0, 0x9F, 0x36, 0x70, 0xFA, 0x86, 0xE9, 0x6D, 0xF5, 0xDA, 0xD3, 0x72, 0xE6, 0xFD, 0x48, 0xE3, 0xBD, 0x73, 0xAC, 0x3A, 0x13, 0x7B, 0xB9, 0xF1, 0x5F};

void decrypt (uint32_t *v,uint32_t allRoundSum){
uint32_t v0=v[0],v1=v[1],sum=allRoundSum,i=0;
uint32_t delta=0xc3c67cdc;
do{
v1-=((v0 << 4)^(v0 >> 5) + v0) ^( sbox[(sum >>11)&0xff]+ sum);
sum-=delta;
v0-=((v1 << 3)^(v1 >> 3) + v1) ^( sbox[(sum &0x3)&0xff]+ sum);
i++;
} while(0x478 >= i);
v[0]=v0;v[1]=v1;
}

uint32_t encrypt (uint32_t *v){
uint32_t v0=v[0],v1=v[1],sum=0,i=0;
uint32_t delta=0xc3c67cdc;
do{
v0+=((v1 << 3)^(v1 >> 3) + v1) ^( sbox[(sum &0x3 )&0xff]+ sum);
sum+=delta;
v1+=((v0 << 4)^(v0 >> 5) + v0) ^( sbox[(sum >>11)&0xff] + sum);
i++;
} while(0x478 >= i);
v[0]=v0;v[1]=v1;
return sum;
}

int main(){
uint32_t v[2]={0x64636261,0x68676665}; //test
uint32_t enc[2]={0x3d2c5b74,0xf06203ec};
uint32_t sum = encrypt(v);

cout<<hex<<v[0]<<" "<<v[1]<<endl;
decrypt(enc,sum);
cout<<hex<<enc[0]<<" "<<enc[1]<<endl;
return 0;
}

//e2ffd8ff 4349580c
//ff d8 ff e2 0c 58 49 43

解出jpg的文件头ff d8 ff e2 0c 58 49 43

又看了一遍第2个文件

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

using namespace std;

vector<uint8_t> sbox = {0x2A, 0x6D, 0xC8, 0xB9, 0xAF, 0xC5, 0x6F, 0x66, 0x6, 0x88, 0x46, 0x31, 0xA0, 0x3D, 0x17, 0x93, 0xE0, 0x3E, 0xF3, 0x60, 0x24, 0x22, 0xEA, 0x14, 0x23, 0x18, 0x57, 0xA8, 0xD7, 0x27, 0xD8, 0xD1, 0xE, 0x3F, 0x20, 0x90, 0x4C, 0xDD, 0x1C, 0x4D, 0x8B, 0x4E, 0x36, 0x41, 0x39, 0x73, 0xB2, 0x9C, 0xB6, 0xE8, 0xC2, 0x34, 0x2B, 0xC, 0x92, 0x1F, 0x8F, 0x7A, 0xFE, 0x83, 0x94, 0x40, 0xD2, 0x79, 0x75, 0x35, 0x9F, 0x3A, 0xD6, 0x84, 0x7B, 0x16, 0x5C, 0xAC, 0x5E, 0xB5, 0x1, 0x37, 0x63, 0xD5, 0xAE, 0x9A, 0x1B, 0xD4, 0x81, 0x21, 0x7D, 0xF1, 0x69, 0xA9, 0x55, 0xBE, 0x42, 0x5A, 0x8A, 0x89, 0xE7, 0xA4, 0x71, 0xB8, 0x45, 0xF5, 0xAA, 0xD0, 0xA5, 0x74, 0xCC, 0xE1, 0xAD, 0x33, 0xEE, 0x28, 0xF, 0xBA, 0x78, 0x2D, 0x50, 0x25, 0xEF, 0xC3, 0xA6, 0x9, 0x49, 0x87, 0xD, 0x91, 0xFB, 0x59, 0x4B, 0xB7, 0x3, 0x8, 0xC0, 0xB1, 0xEB, 0x77, 0xFD, 0x48, 0xBD, 0x43, 0x9B, 0xB0, 0xF7, 0x5D, 0xF2, 0xE3, 0x2F, 0xDB, 0xE5, 0xB, 0x86, 0x13, 0x2C, 0x51, 0x5F, 0x97, 0x6C, 0x4, 0x7E, 0x64, 0x70, 0xCD, 0x72, 0xFA, 0xFC, 0xA2, 0x26, 0x7, 0xEC, 0x98, 0x8C, 0xCB, 0xA7, 0x96, 0x5, 0xD9, 0xF4, 0x2, 0x8D, 0xC1, 0x82, 0xF8, 0x47, 0x9E, 0xBC, 0x99, 0xC6, 0x11, 0xB4, 0x3C, 0xCE, 0x3B, 0xFF, 0x6A, 0xDF, 0x30, 0x76, 0x5B, 0x4A, 0x29, 0xC4, 0x2E, 0xDA, 0x7C, 0xED, 0xE9, 0x61, 0x12, 0x4F, 0x53, 0x9D, 0x62, 0x80, 0xCF, 0x8E, 0x32, 0xCA, 0x95, 0x56, 0x67, 0xC7, 0x58, 0xF0, 0x1A, 0x85, 0xA3, 0xDC, 0xB3, 0xA, 0xA1, 0x0, 0xE6, 0x52, 0x54, 0xF6, 0xAB, 0x15, 0xF9, 0x1D, 0xE4, 0x38, 0x7F, 0x6E, 0x6B, 0xBF, 0x1E, 0xDE, 0xC9, 0xBB, 0x44, 0x19, 0x10, 0xE2, 0xD3, 0x68, 0x65};
void decrypt (uint32_t *v,uint32_t allRoundSum){
uint32_t v0=v[0],v1=v[1],sum=allRoundSum,i=0;
uint32_t delta=0x9d175c01;
do{
v1-=((v0 << 2)^(v0 >> 3) + v0) ^( sbox[(sum >>11)&0xff]+ sum);
sum-=delta;
v0-=((v1 << 4)^(v1 >> 1) + v1) ^( sbox[(sum &0x3)&0xff]+ sum);
i++;
} while(0x478 >= i);
v[0]=v0;v[1]=v1;
}

uint32_t encrypt (uint32_t *v){
uint32_t v0=v[0],v1=v[1],sum=0,i=0;
uint32_t delta=0x9d175c01;
do{
v0+=((v1 << 4)^(v1 >> 1) + v1) ^( sbox[(sum &0x3 )&0xff]+ sum);
sum+=delta;
v1+=((v0 << 2)^(v0 >> 3) + v0) ^( sbox[(sum >>11)&0xff] + sum);
i++;
} while(0x478 >= i);
v[0]=v0;v[1]=v1;
return sum;
}

int main(){
uint32_t v[2]={0x64636261,0x68676665}; //test
uint32_t enc[2]={0x5c97bcbf,0x11bc6542};
uint32_t sum = encrypt(v);
cout<<hex<<v[0]<<" "<<v[1]<<endl;
decrypt(enc,sum);
cout<<hex<<enc[0]<<" "<<enc[1]<<endl;
return 0;
}

//43 5f 50 52 4f 46 49 4c

发现修改的地方有”<<”和”>>”的位移数,delta值,RC4流密钥,密文。

在加密函数中可以发现在函数调用之前的字节码是有特征的,我们可以在内存中搜索这段字节码从而定位操作的位置,下断点,然后运行读取寄存器中的传入的参数。

尝试过用frida,但是后面发现libdebug更加容易,这里是一个frida的测试脚本,只对文件1,2,3进行了测试。

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
//const FUNC_OFFSET = 0x1630  // 1
const FUNC_OFFSET = 0x17C0; // 2
//const FUNC_OFFSET = 0x0167B //3

const pow = [0x89, 0xc6, 0xbf, 0x02, 0x00, 0x00, 0x00, 0xe8] //eax
var powFlag = 0; //4
var shift = []; //4 r>> r<< l>> l<<

const delta = [0x48, 0x89, 0xc7, 0xff, 0xd1]; //esi
var deltaFlag = 0; //1
var deltaData = 0;

const sbox = [0x89, 0xce, 0x48, 0x89, 0xc7, 0x41, 0xff, 0xd0]; //rax:addr 256*4 bytes
var sboxFlag = 0;
var sboxData = [];//ptr

function matchPattern(code,pattern) {
for (let i = 0; i < pattern.length; i++) {
if (code[i] !== pattern[i]) return false;
}
return true;
}

const moduleBase = Process.getModuleByName("beatme").base;
const targetAddr = moduleBase.add(FUNC_OFFSET);

console.log("[*] Waiting to reach function at", targetAddr);

Interceptor.attach(targetAddr, {
onEnter(args) {
try {
console.log("[+] Entered target function, starting Stalker at", targetAddr);
console.log(ptr(args[1]))
Stalker.follow(Process.getCurrentThreadId(), {
transform(iterator) {
let instruction;
while ((instruction = iterator.next()) !== null) {
const addr = instruction.address;
const codeBytes = Memory.readByteArray(addr, 8);
const code = new Uint8Array(codeBytes);
// console.log(`[${addr}] ${instruction}`);
if ((powFlag < 4) && matchPattern(code,pow)) {
console.log("[*] Match pow found at:", addr.sub(moduleBase));
console.log(`[${addr}] ${instruction}`);
iterator.putCallout(function (context) {
if(powFlag >=4) return;
var rax = context.rax;
console.log(`shift: EAX = ${rax.toString(16)}`);
shift[powFlag++] = rax;
})
}
else if (!deltaFlag && matchPattern(code,delta)) {
console.log("[*] Match delta found at:", addr.sub(moduleBase));
console.log(`[${addr}] ${instruction}`);
iterator.putCallout(function (context) {
if(deltaFlag != 0) return;
var rsi = context.rsi;
console.log(`delta: RSI = ${rsi.toString(16)}`);
deltaData = rsi;
deltaFlag++;
})
}
else if (!sboxFlag && matchPattern(code,sbox)) {

console.log("[*] Match sbox found at:", addr.sub(moduleBase));
console.log(`[${addr}] ${instruction}`);
iterator.putCallout(function (context) {
if(sboxFlag != 0)return;
var rax = context.rax;
console.log(`sbox: RAX = ${rax.toString(16)}`);
for (let i = 0; i < 256; i++) {
const value = Memory.readU32(rax.add(i * 4));
sboxData.push(value);
sboxFlag++;
}
})
}
iterator.keep();
}
}
});
} catch (e) {
console.log(e);
}
},
onLeave: function (args) {
console.log(sboxData)
console.log(shift);
console.log(deltaData);

}
});

image

libdebug进行自动调试,获取数据并解密,在game文件夹下运行。注意!因为一些原因一次性跑完全部文件会在4000多个的时候报错资源耗尽。所以把解密分成了四段,手动修改并运行四次脚本。大概在运行两段后其实就已经可以得到flag。

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
from libdebug import debugger
from libdebug import libcontext
from ctypes import *
import os
from struct import pack
from tqdm import tqdm

def decrypt(v, key,delta,shift):
v0, v1 = c_uint32(v[0]), c_uint32(v[1])

total = c_uint32(delta * 0x479)
for i in range(1145):
v1.value -= (((v0.value << shift[3]) ^ (v0.value >> shift[2])) + v0.value) ^ (total.value + key[(total.value>>11) & 0xff])
total.value -= delta
v0.value -= (((v1.value << shift[0]) ^ (v1.value >> shift[1])) + v1.value) ^ (total.value + key[total.value & 3])

return v0.value, v1.value

def one(i):
old_cwd = os.getcwd()
path = f"./{i}"
os.chdir(path)
d = debugger("./beatme",auto_interrupt_on_command=True)
try:
p = d.run()

sl = lambda d: p.sendline(d)

b = lambda *a, **kw: d.breakpoint(*a, **kw)
c = lambda: d.cont()
wait = lambda: d.wait()
find = lambda *a, **kw: d.memory.find(*a, **kw)
db = lambda addr: d.breakpoints[addr].disable()

pow_pattern = [0x89, 0xc6, 0xbf, 0x02, 0x00, 0x00, 0x00, 0xe8] #eax 4 r>> r<< l>> l<<
shift = []

delta_pattern = [0x48,0x89,0xc7,0xff,0xd1,0x4c,0x8b,0x05] #esi
delta = None

sbox_pattern = [0x89, 0xce, 0x48, 0x89, 0xc7, 0x41, 0xff, 0xd0] #rax:addr 256*4 bytes
sbox =[]

enc_pattern1 = [[0x8b,0x45,0xa8,0x3d],[0x8b,0x45,0xac,0x3d]]
encData=[]

sl(b"abcdefgh")

addr_enc =[]
for i in range(2):
addr_enc.append(find(bytes(enc_pattern1[i]),file="beatme"))

addr_pow = find(bytes(pow_pattern),file="beatme")

addr_delta = find(bytes(delta_pattern),file="beatme")

addr_sbox = find(bytes(sbox_pattern),file="beatme")

b_pow =[]
for i in range(4):
b_pow.append(b(addr_pow[i],file="beatme"))

for i in range(4):
c()
wait()
eax = d.regs.eax
shift.append(eax)
rip = d.regs.rip
db(rip)

b_delta = b(addr_delta[0],file="beatme")
c()
wait()
delta = d.regs.esi
db(d.regs.rip)

b_sbox = b(addr_sbox[0],file="beatme")
c()
wait()
rax = d.regs.rax
sbox = d.memory[rax,256*4]
db(d.regs.rip)

b_enc =[]
for i in range(2):
a = d.memory[addr_enc[i][0] + 4, 4]
encData.append(int.from_bytes(a,"little"))

key =[]
for i in range(0,len(sbox),4):
key.append(int.from_bytes(sbox[i:i+4:],"little"))

a,b=decrypt(encData,key,delta,shift)

if d.dead:
print(f"The process exited with signal {d.exit_signal}")
print(f"The process exited with code {d.exit_code}")
os.chdir(old_cwd)
d.kill()
return a,b
except Exception as e:
os.chdir(old_cwd)
print(f"[!] 第 {i} 个样本失败: {e}")
d.kill()
return None

result_bytes = bytearray()

#[(1, 2856), (2857, 5712), (5713, 8568), (8569, 11423)]
for i in tqdm(range(1, 2856), desc="process"):
res = one(i)
if res is None:
break
a, b = res
result_bytes += pack("<I", a)
result_bytes += pack("<I", b)

with open("output.jpg", "ab") as f:
f.write(result_bytes)