hws冬令营选拔赛部分wp

就做了一道题拿了1血,后面就忘记做了,复现学到东西的题

[rev]babyre

hook了一个从ring3到ring0的函数,所以v9调用的其实是自己的函数。

通过调试没找到那个函数,只能在函数列表一个一个寻找(也可以过滤函数长度,找了一下不是库函数就是直接jmp的函数,所以应该很容易过滤)

找到了sub_412A20,其中有ZwSetInformatinoThread反调试,这个函数如果执行到最后恰好返回0x7ff,我tm直接nop反调试

然后加载了一个资源文件并且解密,然后是sm4加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

import hashlib
import base64
import marshal
import dis
from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes,bytes_to_long
from pysm4 import decrypt

cipher = bytes([234, 99, 88, 183, 140, 226, 161, 233, 197, 41, 143, 83, 232, 8, 50, 89, 175, 27, 103, 174, 217, 218, 207, 196, 114, 255, 177, 236, 118, 115, 243, 6])
key = b'Ez_5M4_C1pH@r!!!'
p = decrypt(bytes_to_long(cipher[:16]),bytes_to_long(key))
p2 = decrypt(bytes_to_long(cipher[16:]),bytes_to_long(key))
print(hex(p),hex(p2))
print(long_to_bytes(p)+long_to_bytes(p2))

[rev]Enigma

异常虚拟机

通过SetUnhandledExceptionFilter进行了无效指令的处理和反调试,SetUnhandledExceptionFilter主要通过ZwQueryInformationProcess查询调试器,可以patch掉ZwQueryInformationProcess的代码,具体是在ZwQueryInformationProcess下断点,断下时如果第二个参数为7,infoClass=7,就回溯到调用者函数,把je改为jmp

https://www.cnblogs.com/zpchcbd/p/12079166.html

反汇编脚本

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

import hashlib
import base64
import marshal
import dis

opcs = [85, 139, 236, 83, 86, 87, 104, 48, 22, 64, 0, 255, 21, 0, 32, 68, 0, 199, 255, 4, 1, 0, 51, 201, 131, 249, 32, 125, 23, 199, 255, 0, 1, 17, 199, 255, 4, 1, 31, 137, 4, 141, 112, 122, 69, 0, 199, 255, 2, 3, 235, 228, 51, 201, 131, 249, 32, 125, 45, 139, 28, 141, 112, 122, 69, 0, 139, 20, 141, 116, 122, 69, 0, 138, 130, 76, 122, 69, 0, 136, 131, 224, 121, 69, 0, 138, 131, 76, 122, 69, 0, 136, 130, 224, 121, 69, 0, 199, 255, 0, 3, 2, 235, 206, 51, 201, 131, 249, 32, 125, 53, 138, 153, 224, 121, 69, 0, 199, 255, 4, 2, 31, 199, 255, 7, 2, 3, 139, 241, 70, 131, 230, 31, 138, 150, 224, 121, 69, 0, 128, 226, 224, 129, 226, 255, 0, 0, 0, 199, 255, 8, 4, 5, 10, 218, 136, 153, 4, 122, 69, 0, 65, 235, 198, 160, 4, 122, 69, 0, 162, 40, 122, 69, 0, 185, 1, 0, 0, 0, 131, 249, 32, 125, 40, 138, 153, 4, 122, 69, 0, 139, 241, 199, 255, 3, 5, 50, 158, 4, 122, 69, 0, 139, 241, 199, 255, 4, 5, 3, 50, 158, 240, 104, 69, 0, 136, 153, 40, 122, 69, 0, 65, 235, 211, 95, 94, 91, 93, 195]
ip = 0
start=True
regs = ['invalid','eax','ebx','ecx','edx','esi']
while ip<len(opcs):
rip = ip+0x4018f0
dip = 0
if opcs[ip]==0xc7 and ip+1<len(opcs) and opcs[ip+1]==0xff:
opc = opcs[ip+2]
op1 = opcs[ip+3]
op2 = opcs[ip+4]
print('%08x:'%rip,end="")

if opc==0:
dip=5
print('add %s,%d'%(regs[op1],op2))
elif opc==1:
dip=5
print('sub %s,%d'%(regs[op1],op2))
elif opc==2:
dip=4
print('inc %s'%regs[op1])
elif opc==3:
print('dec %s'%regs[op1])
dip=4
elif opc==5:
print('and %s,%d'%(regs[op1],op2))
dip=5
elif opc==6:
print('or %s,%d'%(regs[op1],op2))
dip=5
elif opc==7:
print('shl %s,%d'%(regs[op1],op2))
dip=5
elif opc==8:
print('shr %s,%d'%(regs[op1],op2))
dip=5
else:
print('nop')
dip=2
start=True
else:
if start:
print('%08x:%x:valid code'%(rip,opcs[ip]))
start=False
dip=1
ip+=dip

patch程序方法:可以先都patch成0x90,这样就可以patch 汇编了。更好的方法当然是使用一个汇编引擎(已知pwntools)

patch之后就可以直接f5了(~ ̄▽ ̄)~(~ ̄▽ ̄)~(~ ̄▽ ̄)~(~ ̄▽ ̄)~(~ ̄▽ ̄)~

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
char sub_4018F0()
{
int v0; // eax
int i; // ecx
int j; // ecx
int v3; // ebx
int v4; // edx
int k; // ecx
char result; // al
int l; // ecx

SetUnhandledExceptionFilter(TopLevelExceptionFilter);
LOBYTE(v0) = 0;
for ( i = 0; i < 32; ++i )
{
v0 = ((_BYTE)v0 + 17) & 0x1F;
dword_457A70[i] = v0;
}
for ( j = 0; j < 32; j += 2 )
{
v3 = dword_457A70[j];
v4 = dword_457A74[j];
byte_4579E0[v3] = byte_457A4C[v4];
byte_4579E0[v4] = byte_457A4C[v3];
}
for ( k = 0; k < 32; ++k )
byte_457A04[k] = ((unsigned __int8)(byte_4579E0[((_BYTE)k + 1) & 0x1F] & 0xE0) >> 5) | (8 * (byte_4579E0[k] & 0x1F));
result = byte_457A04[0];
byte_457A28[0] = byte_457A04[0];
for ( l = 1; l < 32; ++l )
byte_457A28[l] = aBier[l & 3] ^ byte_457A04[l - 1] ^ byte_457A04[l];
return result;
}

首先是一个群上面的移位,然后整体循环左移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

import hashlib
import base64
import marshal
import dis
import unicorn

s = '938b8f431268f7907a4b6e421301b42120738d68cb19fcf8b26bc4abc89b8d22'
arr = [int(s[i:i+2],base=16) for i in range(0,len(s),2)]
xord = [i for i in b'Bier']
for i in range(1,len(arr)):
arr[i]=arr[i]^arr[i-1]^xord[i%4]
narr = [0]*len(arr)
for i in range(len(arr)):
narr[i]=(arr[i]>>3)|(arr[(i-1)&0x1f]<<5)
narr[i]&=0xff
ind = [17]+[0]*31
print(bytes(narr))
for i in range(1,31):
ind[i]=(ind[i-1]+17)&0x1f
for i in range(0,len(narr),2):
tmp = narr[ind[i]]
narr[ind[i]]=narr[ind[i+1]]
narr[ind[i+1]]=tmp
print(bytes(narr))

[rev]child_protect

既然是child_protect,直接找CreateProcess,交叉引用找到了父进程主函数sub_413670,然后pid交叉引用找到了DebugActiveProcess,sub_413D10下面是主进程对子进程进行处理的函数sub_411415

查了一下GetLastError的ErrorCode,183恰好是文件已存在,也就是说父子进程通过这个判断自己的身份

根据父进程patch子进程,得到流程是先异或再byteswap再tea再byteswap

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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <math.h>
// #include "defs.h"
// #include <setimp.h>
int key[8];
void printArray(const char *name,uint8_t *v,size_t len)
{
printf("========%s=========\n",name);
for(size_t i=0;i<len;i++){
printf("0x%02X,",v[i]);
}
printf("\n=================\n");
}
int sub_412FB0()
{
int result;
// eax
int k;
// [esp+D0h] [ebp-E4h]
int j;
// [esp+DCh] [ebp-D8h]
int i;
// [esp+E8h] [ebp-CCh]
int v4[10];
// [esp+11Ch] [ebp-98h]
int v5[10];
// [esp+144h] [ebp-70h]
int v6[8];
// [esp+16Ch] [ebp-48h]
int v7[9];
// [esp+18Ch] [ebp-28h]
v6[0] = 2130706575;
v6[1] = 1799636093;
v6[2] = 1435019980;
v6[3] = -1351037338;
v6[4] = -1720747942;
v6[5] = -212893566;
v6[6] = -1812289297;
v6[7] = -381726905;
v7[0] = -449338949;
v7[1] = 1166434102;
v7[2] = -1917020786;
v7[3] = -603841535;
v7[4] = 1193330650;
v7[5] = -295274829;
v7[6] = 2021562342;
v7[7] = -1511690567;
v5[0] = -557566690;
v5[1] = 854106805;
v5[2] = 827418122;
v5[3] = 2071911752;
v5[4] = 1115606310;
v5[5] = 452882457;
v5[6] = 1918099577;
v5[7] = 421130192;
v4[0] = 445079886;
v4[1] = 2056584266;
v4[2] = -357270445;
v4[3] = 1148562038;
v4[4] = 1253939174;
v4[5] = 1597303268;
v4[6] = -598138600;
v4[7] = -13445532;
result = 0;
for ( i = 0; i < 16; ++i )
{
key[i % 8] += v6[i] ^ 0x54647484;
for ( j = 0; j < 8; ++j )
{
key[j] = (v7[j] ^ v6[j]) << j;
v6[j] += v7[j] ^ v5[j];
v7[j] -= v6[j] ^ v5[7 - j];
}
key[i % 8] += v5[i % 8] ^ (v4[i % 8] + v6[i]);
for ( k = 0; k < 8; ++k )
{
v5[k] *= v4[k];
v4[k] += v5[k];
}
result = i + 1;
}
return result;
}
void encrypt (uint32_t* v, uint32_t* k)
{
uint32_t v0=v[0], v1=v[1], sum=0, i;
/* set up */
uint32_t delta=0x9e3779b9;
/* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];
/* cache key */
for (i=0; i < 32; i++)
{
/* basic cycle start */
sum += delta;
v0 += ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
v1 += ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
}
/* end cycle */
v[0]=v0;
v[1]=v1;
}
void decrypt (uint32_t* v, uint32_t* k)
{
uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;
/* set up */
uint32_t delta=0x9e3779b9;
/* a key schedule constant */
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];
/* cache key */
for (i=0; i<32; i++)
{
/* basic cycle start */
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
}
/* end cycle */
v[0]=v0;
v[1]=v1;
}
uint32_t byteSwap(uint32_t x){
return ((x>>8)&0xff00)|((x<<8)&0xff0000)|((x>>24)&0xff)|((x<<24)&0xff000000);
}
int main()
{
sub_412FB0();
// printArray("key",(uint8_t*)key,32);
printf("0x%08x,0x%08x,0x%08x,0x%08x\n",key[0],key[1],key[2],key[3]);
uint8_t v3[33];
v3[0] = 237;
v3[1] = 233;
v3[2] = 139;
v3[3] = 59;
v3[4] = 210;
v3[5] = 133;
v3[6] = 231;
v3[7] = 235;
v3[8] = 81;
v3[9] = 22;
v3[10] = 80;
v3[11] = 122;
v3[12] = 177;
v3[13] = 220;
v3[14] = 93;
v3[15] = 9;
v3[16] = 69;
v3[17] = 174;
v3[18] = 185;
v3[19] = 21;
v3[20] = 77;
v3[21] = 141;
v3[22] = 255;
v3[23] = 80;
v3[24] = 222;
v3[25] = 224;
v3[26] = 188;
v3[27] = 139;
v3[28] = 155;
v3[29] = 188;
v3[30] = 254;
v3[31] = 225;
uint32_t v[2];
uint32_t k[4];
uint32_t xord = 0x73FF8CA6;
uint32_t dif = 0x50FFE544;
for(size_t i=0;i<32;i+=8){
v[0]=byteSwap(*(uint32_t*)&v3[i]);
v[1]=byteSwap(*(uint32_t*)&v3[i+4]);
printf("0x%08x,0x%08x\n",v[0],v[1]);
decrypt(v,key);
v[0]^=xord;
xord-=dif;
v[1]^=xord;
xord-=dif;
printArray("v",(uint8_t*)v,8);
*(uint32_t*)&v3[i]=byteSwap(v[0]);
*(uint32_t*)&v3[i+4]=byteSwap(v[1]);
}
printf("%s\n",v3);
return 0;
}