2011年成都信息工程学院第二季极客大挑战逆向第三题Game破文

【文章标题】: 2011年成都信息工程学院第二季极客大挑战逆向第三题Game破文
【文章作者】: JoyChou
【软件名称】: Game
【软件大小】: 176KB
【下载地址】: http://www.cnblogs.com/Joy7/admin/Files.aspx
【加壳方式】: 无壳
【保护方式】: 注册码保护
【编写语言】: Microsoft Visual C++ 5.0 [Debug]
【使用工具】: PEiD,OD,IDA
【操作平台】: XP SP3
【软件介绍】: 一个简单的猜数字游戏
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
首先用PEiD查壳,VC++写的。
运行下看看,程序叫直接猜数,随便输入123456,然后显示try again
接下来用OD载入,查找again字符串。这个没有对提示信息隐藏,能用OD插件搜索到。
也没可以敏感的API函数下断,例如 bp MessageBoxA
这里菜鸟就用消息跟踪吧。效果和上面一样。主要是起个抛砖引玉的作用。

首先F9运行,输入假码后,不点击“我猜”按钮,然后在OD菜单栏查看窗口,这“我猜”按钮处右键设置ClassProc消息断点

  1 再选择202,再点击“我猜”按钮,程序就断下来了,不过是在系统领空,接着ALT+F9,就可以返回到程序领空
  2 00401113 |. 6A 10 push 10 ; /Count = 10 (16.)
  3 00401115 |. 8D45 EC lea eax,dword ptr ss:[ebp-14] ; |
  4 00401118 |. 50 push eax ; |Buffer
  5 00401119 |. 68 E9030000 push 3E9 ; |ControlID = 3E9 (1001.)
  6 0040111E |. 8B4D 08 mov ecx,dword ptr ss:[ebp+8] ; |
  7 00401121 |. 51 push ecx ; |hWnd
  8 00401122 |. FF15 C4A24200 call dword ptr ds:[<&USER32.GetDlgItemTextA>>; \GetDlgItemTextA
  9 00401128 |. 3BF4 cmp esi,esp
 10 0040112A |. E8 91030000 call Game.004014C0
 11 0040112F |. 8D55 EC lea edx,dword ptr ss:[ebp-14] ; 假码
 12 00401132 |. 52 push edx ; 假码入栈
 13 00401133 |. E8 D7FEFFFF call Game.0040100F
 14 00401138 |. 83C4 04 add esp,4
 15 0040113B |. 85C0 test eax,eax
 16 0040113D |. 74 21 je short Game.00401160
 17 0040113F |. 8BF4 mov esi,esp
 18 00401141 |. 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
 19 00401143 |. 68 3C204200 push Game.0042203C ; |key:
 20 00401148 |. 68 2C204200 push Game.0042202C ; |is your input
 21 0040114D |. 8B45 08 mov eax,dword ptr ss:[ebp+8] ; |
 22 00401150 |. 50 push eax ; |hOwner
 23 00401151 |. FF15 C8A24200 call dword ptr ds:[<&USER32.MessageBoxA>] ; \MessageBoxA
 24 00401157 |. 3BF4 cmp esi,esp
 25 00401159 |. E8 62030000 call Game.004014C0
 26 0040115E |. EB 1F jmp short Game.0040117F
 27 00401160 |> 8BF4 mov esi,esp
 28 00401162 |. 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
 29 00401164 |. 68 24204200 push Game.00422024 ; |try:
 30 00401169 |. 68 1C204200 push Game.0042201C ; |again
 31 0040116E |. 8B4D 08 mov ecx,dword ptr ss:[ebp+8] ; |
 32 00401171 |. 51 push ecx ; |hOwner
 33 00401172 |. FF15 C8A24200 call dword ptr ds:[<&USER32.MessageBoxA>] ; \MessageBoxA
 34 00401178 |. 3BF4 cmp esi,esp //返回到这,向上看就懂了
 35 
 36 
 37 F7进入00401133 这个关键call
 38 00401320 /> \55 push ebp
 39 00401321 |. 8BEC mov ebp,esp
 40 00401323 |. 83EC 58 sub esp,58
 41 00401326 |. 53 push ebx
 42 00401327 |. 56 push esi
 43 00401328 |. 57 push edi
 44 00401329 |. 8D7D A8 lea edi,dword ptr ss:[ebp-58] ; HDg
 45 0040132C |. B9 16000000 mov ecx,16
 46 00401331 |. B8 CCCCCCCC mov eax,CCCCCCCC
 47 00401336 |. F3:AB rep stos dword ptr es:[edi]
 48 00401338 |. C645 EC 00 mov byte ptr ss:[ebp-14],0
 49 0040133C |. 33C0 xor eax,eax
 50 0040133E |. 8945 ED mov dword ptr ss:[ebp-13],eax
 51 00401341 |. 8945 F1 mov dword ptr ss:[ebp-F],eax
 52 00401344 |. 8945 F5 mov dword ptr ss:[ebp-B],eax
 53 00401347 |. 66:8945 F9 mov word ptr ss:[ebp-7],ax
 54 0040134B |. 8845 FB mov byte ptr ss:[ebp-5],al
 55 0040134E |. 8B4D 08 mov ecx,dword ptr ss:[ebp+8] ; 假码
 56 00401351 |. 51 push ecx ; 假码入栈
 57 00401352 |. E8 A9010000 call Game.00401500 ; 计算假码长度返回给eax,这里就不进去了
 58 00401357 |. 83C4 04 add esp,4
 59 0040135A |. 8945 FC mov dword ptr ss:[ebp-4],eax ; ebp-4为假码长度
 60 0040135D |. C745 E8 01000>mov dword ptr ss:[ebp-18],1 ; i=i+2,i初始化为1
 61 00401364 |. EB 09 jmp short Game.0040136F
 62 00401366 |> 8B55 E8 /mov edx,dword ptr ss:[ebp-18]
 63 00401369 |. 83C2 02 |add edx,2
 64 0040136C |. 8955 E8 |mov dword ptr ss:[ebp-18],edx
 65 0040136F |> 8B45 E8 mov eax,dword ptr ss:[ebp-18]
 66 00401372 |. 3B45 FC |cmp eax,dword ptr ss:[ebp-4]
 67 00401375 |. 7D 17 |jge short Game.0040138E ; eax大于等于假码长度就跳出循环
 68 00401377 |. 8B4D 08 |mov ecx,dword ptr ss:[ebp+8] ; ebp+8指向假码
 69 0040137A |. 034D E8 |add ecx,dword ptr ss:[ebp-18] ; 取偶数位,也就是s[1],s[3],s[5]数组表示
 70 0040137D |. 0FBE11 |movsx edx,byte ptr ds:[ecx] ; 依次给edx
 71 00401380 |. 83FA 32 |cmp edx,32 ; 和2比较
 72 00401383 |. 74 07 |je short Game.0040138C ; 相等就跳
 73 00401385 |. 33C0 |xor eax,eax
 74 00401387 |. E9 B4000000 |jmp Game.00401440 ; 跳向错误
 75 0040138C |>^ EB D8 \jmp short Game.00401366
 76 
 77 所以程序先处理偶数位,要求就是每位偶数位都是2,下面就是处理奇数位,但是处理奇数位的时候用了一个反汇编代码比较多的表示方法
 78 
 79 a % 2 == 0,当然0,24,6等余数都是0,所以表示的是奇数。
 80 
 81 if(a % 2 == 0)
 82 {
 83 //do something
 84 }
 85 对应的汇编指令比较多些
 86 
 87 Assembly code
 88 
 89 00A31395 mov eax,dword ptr [a] 
 90 00A31398 and eax,80000001h 
 91 00A3139D jns main+34h (0A313A4h) 
 92 00A3139F dec eax 
 93 00A313A0 or eax,0FFFFFFFEh 
 94 00A313A3 inc eax 
 95 00A313A4 text eax,eax
 96 00A313A7 jne main+40h (0A313B0h) 
 97 
 98 如果这样处理
 99 if(a & 0x1 == 1)
100 {
101 //do something
102 }
103 对应的汇编指令好少啊~
104 
105 Assembly code    
106 
107 002D1395 mov eax,dword ptr [a] 
108 002D1398 and eax,1 
109 002D139B je main+34h (2D13A4h)
110 相比之下,我想出题者肯定是想增加下难度而已。菜鸟再次飘过~~下面继续分析奇数位~~
111 
112 接下来的代码就是将奇数位放在ebp-14,这里菜鸟就不仔细分析了,有时候可以直接步过看结果,猜测算法,大大减少了分析代码的时间
113 0040138E |> \C745 E8 00000>mov dword ptr ss:[ebp-18],0 ; i=0
114 00401395 |. EB 09 jmp short Game.004013A0
115 00401397 |> 8B45 E8 /mov eax,dword ptr ss:[ebp-18]
116 0040139A |. 83C0 01 |add eax,1 ; i++
117 0040139D |. 8945 E8 |mov dword ptr ss:[ebp-18],eax
118 004013A0 |> 8B4D E8 mov ecx,dword ptr ss:[ebp-18]
119 004013A3 |. 3B4D FC |cmp ecx,dword ptr ss:[ebp-4] ; i和假码长度比较
120 004013A6 |. 7D 2A |jge short Game.004013D2 ; 大于等于就跳
121 004013A8 |. 8B55 E8 |mov edx,dword ptr ss:[ebp-18]
122 004013AB |. 81E2 01000080 |and edx,80000001 ; edx=i^80000001
123 004013B1 |. 79 05 |jns short Game.004013B8 ; SF=0就跳
124 004013B3 |. 4A |dec edx
125 004013B4 |. 83CA FE |or edx,FFFFFFFE
126 004013B7 |. 42 |inc edx
127 004013B8 |> 85D2 |test edx,edx
128 004013BA |. 75 14 |jnz short Game.004013D0
129 004013BC |. 8B45 E8 |mov eax,dword ptr ss:[ebp-18]
130 004013BF |. 99 |cdq
131 004013C0 |. 2BC2 |sub eax,edx
132 004013C2 |. D1F8 |sar eax,1
133 004013C4 |. 8B4D 08 |mov ecx,dword ptr ss:[ebp+8]
134 004013C7 |. 034D E8 |add ecx,dword ptr ss:[ebp-18]
135 004013CA |. 8A11 |mov dl,byte ptr ds:[ecx]
136 004013CC |. 885405 EC |mov byte ptr ss:[ebp+eax-14],dl
137 004013D0 |>^ EB C5 \jmp short Game.00401397
138 004013D2 |> 8D45 EC lea eax,dword ptr ss:[ebp-14]
139 
140 下面就是处理奇数位~~
141 004013D2 |> \8D45 EC lea eax,dword ptr ss:[ebp-14]
142 004013D5 |. 50 push eax ; 奇数位入栈处理
143 004013D6 |. E8 2AFCFFFF call Game.00401005 ; 这个call很重要,进去看看
144 004013DB |. 83C4 04 add esp,4
145 004013DE |. 85C0 test eax,eax ; eax返回应该不为0
146 004013E0 |. 74 2D je short Game.0040140F ; 跳向失败,不让它跳
147 004013E2 |. 8D4D EC lea ecx,dword ptr ss:[ebp-14]
148 004013E5 |. 51 push ecx
149 004013E6 |. E8 1AFCFFFF call Game.00401005 ; 和上面call一样,也就是处理两次
150 004013EB |. 83C4 04 add esp,4
151 004013EE |. 85C0 test eax,eax ; eax返回应该不为0
152 004013F0 |. 74 17 je short Game.00401409 ; 跳向失败,不让它跳
153 004013F2 |. 8D55 EC lea edx,dword ptr ss:[ebp-14]
154 004013F5 |. 52 push edx
155 004013F6 |. E8 05010000 call Game.00401500 ; 计算ebp-14指向字符串的长度,再IDA里可以直接看到strlen这个函数名字
156 004013FB |. 83C4 04 add esp,4
157 004013FE |. 83F8 04 cmp eax,4 ; 和4比较
158 00401401 |. 74 04 je short Game.00401407 ; 不相等就跳向失败
159 00401403 |. 33C0 xor eax,eax
160 00401405 |. EB 39 jmp short Game.00401440 ; 跳向失败
161 00401407 |> EB 04 jmp short Game.0040140D ; 长度等于4就跳向这
162 00401409 |> 33C0 xor eax,eax
163 0040140B |. EB 33 jmp short Game.00401440
164 0040140D |> EB 04 jmp short Game.00401413 ; 再跳到这
165 0040140F |> 33C0 xor eax,eax
166 00401411 |. EB 2D jmp short Game.00401440
167 00401413 |> 0FBE45 EC movsx eax,byte ptr ss:[ebp-14] ; 再到这,取奇数第一位
168 00401417 |. 0FBE4D ED movsx ecx,byte ptr ss:[ebp-13] ; 奇数第二位
169 0040141B |. 3BC1 cmp eax,ecx
170 0040141D |. 7E 1F jle short Game.0040143E ; 跳向失败,故第一位应该大于第二位
171 0040141F |. 0FBE55 ED movsx edx,byte ptr ss:[ebp-13]
172 00401423 |. 0FBE45 EE movsx eax,byte ptr ss:[ebp-12] ; 奇数第三位
173 00401427 |. 3BD0 cmp edx,eax
174 00401429 |. 7D 13 jge short Game.0040143E ; 跳向失败,故第二位应该小于第三位
175 0040142B |. 0FBE4D EE movsx ecx,byte ptr ss:[ebp-12]
176 0040142F |. 0FBE55 EF movsx edx,byte ptr ss:[ebp-11] ; 奇数位第四位
177 00401433 |. 3BCA cmp ecx,edx
178 00401435 |. 75 07 jnz short Game.0040143E ; 跳向失败,故第三位应该等于第四位
179 00401437 |. B8 01000000 mov eax,1
180 0040143C |. EB 02 jmp short Game.00401440
181 0040143E |> 33C0 xor eax,eax ; 目的就是跳过这代码,使eax不等于0
182 00401440 |> 5F pop edi
183 00401441 |. 5E pop esi
184 00401442 |. 5B pop ebx
185 00401443 |. 83C4 58 add esp,58
186 00401446 |. 3BEC cmp ebp,esp
187 00401448 |. E8 73000000 call Game.004014C0 ; 没用call
188 0040144D |. 8BE5 mov esp,ebp
189 0040144F |. 5D pop ebp
190 00401450 \. C3 retn
191 
192 这F7进入004013D6 这个call,很关键的call,
193 也就是输入的要求:首先输入的数字必须满足
194 假码的第三位=第三位-第二位,结果加上0x30,最后的结果必须和第一位相等,然后依次循环,即a[3]-a[2]=a[1]
195 等价于第三位=第一位+第二位
196 运行一次,减少一位
197 要运行2次,最后和4比较,故奇数位是6位
198 比如:
199 1235 call一次 变成112 ,就是后者减去前者
200 如果第二次就是 01
201 
202 00401200 /> \55 push ebp
203 00401201 |. 8BEC mov ebp,esp
204 00401203 |. 83EC 44 sub esp,44
205 00401206 |. 53 push ebx
206 00401207 |. 56 push esi
207 00401208 |. 57 push edi
208 00401209 |. 8D7D BC lea edi,dword ptr ss:[ebp-44]
209 0040120C |. B9 11000000 mov ecx,11
210 00401211 |. B8 CCCCCCCC mov eax,CCCCCCCC
211 00401216 |. F3:AB rep stos dword ptr es:[edi]
212 00401218 |. C745 FC 00000>mov dword ptr ss:[ebp-4],0
213 0040121F |. EB 09 jmp short Game.0040122A
214 00401221 |> 8B45 FC /mov eax,dword ptr ss:[ebp-4]
215 00401224 |. 83C0 01 |add eax,1
216 00401227 |. 8945 FC |mov dword ptr ss:[ebp-4],eax
217 0040122A |> 8B4D 08 mov ecx,dword ptr ss:[ebp+8] ; 指向奇数位假码
218 0040122D |. 034D FC |add ecx,dword ptr ss:[ebp-4] ; 循环变量
219 00401230 |. 0FBE51 02 |movsx edx,byte ptr ds:[ecx+2]
220 00401234 |. 85D2 |test edx,edx ; 读取前4个
221 00401236 |. 74 2C |je short Game.00401264
222 00401238 |. 8B45 08 |mov eax,dword ptr ss:[ebp+8]
223 0040123B |. 0345 FC |add eax,dword ptr ss:[ebp-4]
224 0040123E |. 0FBE08 |movsx ecx,byte ptr ds:[eax] ; 取s[0]
225 00401241 |. 8B55 08 |mov edx,dword ptr ss:[ebp+8]
226 00401244 |. 0355 FC |add edx,dword ptr ss:[ebp-4]
227 00401247 |. 0FBE42 02 |movsx eax,byte ptr ds:[edx+2] ; 取s[2]
228 0040124B |. 8B55 08 |mov edx,dword ptr ss:[ebp+8]
229 0040124E |. 0355 FC |add edx,dword ptr ss:[ebp-4]
230 00401251 |. 0FBE52 01 |movsx edx,byte ptr ds:[edx+1] ; 取s[1]
231 00401255 |. 2BC2 |sub eax,edx ; s[2] = s[2]-s[1]
232 00401257 |. 83C0 30 |add eax,30 ; s[2]+0x30
233 0040125A |. 3BC8 |cmp ecx,eax ; ecx必须等于eax,以后依次循环
234 0040125C |. 74 04 |je short Game.00401262
235 0040125E |. 33C0 |xor eax,eax
236 00401260 |. EB 7E |jmp short Game.004012E0
237 00401262 |>^ EB BD \jmp short Game.00401221
238 00401264 |> 8B45 08 mov eax,dword ptr ss:[ebp+8] ; 假码
239 00401267 |. 0345 FC add eax,dword ptr ss:[ebp-4]
240 0040126A |. 0FBE48 01 movsx ecx,byte ptr ds:[eax+1] ; s[3]
241 0040126E |. 8B55 08 mov edx,dword ptr ss:[ebp+8]
242 00401271 |. 0355 FC add edx,dword ptr ss:[ebp-4]
243 00401274 |. 0FBE02 movsx eax,byte ptr ds:[edx] ; s[2]
244 00401277 |. 2BC8 sub ecx,eax
245 00401279 |. 83C1 30 add ecx,30
246 0040127C |. 8B55 08 mov edx,dword ptr ss:[ebp+8]
247 0040127F |. 0355 FC add edx,dword ptr ss:[ebp-4]
248 00401282 |. 0FBE42 FF movsx eax,byte ptr ds:[edx-1]
249 00401286 |. 2BC8 sub ecx,eax ; 使得ecx=0
250 00401288 |. 85C9 test ecx,ecx
251 0040128A |. 74 04 je short Game.00401290 ; 不跳就错误了
252 0040128C |. 33C0 xor eax,eax
253 0040128E |. EB 50 jmp short Game.004012E0
254 00401290 |> C745 FC 00000>mov dword ptr ss:[ebp-4],0
255 00401297 |. EB 09 jmp short Game.004012A2
256 00401299 |> 8B4D FC /mov ecx,dword ptr ss:[ebp-4]
257 0040129C |. 83C1 01 |add ecx,1
258 0040129F |. 894D FC |mov dword ptr ss:[ebp-4],ecx
259 004012A2 |> 8B55 08 mov edx,dword ptr ss:[ebp+8]
260 004012A5 |. 0355 FC |add edx,dword ptr ss:[ebp-4]
261 004012A8 |. 0FBE42 01 |movsx eax,byte ptr ds:[edx+1]
262 004012AC |. 85C0 |test eax,eax
263 004012AE |. 74 22 |je short Game.004012D2
264 004012B0 |. 8B4D 08 |mov ecx,dword ptr ss:[ebp+8]
265 004012B3 |. 034D FC |add ecx,dword ptr ss:[ebp-4]
266 004012B6 |. 0FBE51 01 |movsx edx,byte ptr ds:[ecx+1] ; s[1]
267 004012BA |. 8B45 08 |mov eax,dword ptr ss:[ebp+8]
268 004012BD |. 0345 FC |add eax,dword ptr ss:[ebp-4]
269 004012C0 |. 0FBE08 |movsx ecx,byte ptr ds:[eax] ; s[0]
270 004012C3 |. 2BD1 |sub edx,ecx ; s[1]-s[0]
271 004012C5 |. 83C2 30 |add edx,30 ; s[1]+0x30
272 004012C8 |. 8B45 08 |mov eax,dword ptr ss:[ebp+8]
273 004012CB |. 0345 FC |add eax,dword ptr ss:[ebp-4]
274 004012CE |. 8810 |mov byte ptr ds:[eax],dl ; 将计算结果覆盖之前的奇数
275 004012D0 |.^ EB C7 \jmp short Game.00401299
276 004012D2 |> 8B4D 08 mov ecx,dword ptr ss:[ebp+8]
277 004012D5 |. 034D FC add ecx,dword ptr ss:[ebp-4]
278 004012D8 |. C601 00 mov byte ptr ds:[ecx],0 ; 最后一位置为0,即少一位
279 004012DB |. B8 01000000 mov eax,1
280 004012E0 |> 5F pop edi
281 004012E1 |. 5E pop esi
282 004012E2 |. 5B pop ebx
283 004012E3 |. 8BE5 mov esp,ebp
284 004012E5 |. 5D pop ebp
285 004012E6 \. C3 retn

最后就是算法总结:
首先输入的数字必须满足
假码的第三位=第三位-第二位,结果加上0x30,最后的结果必须和第一位相等,然后依次循环,即a[3]-a[2]=a[1]

即第三位-第二位=第一位,依次循环 等价于第三位=第一位+第二位
call sub_401005看懂这个函数很关键啊,运行一次,减少一位
要运行2次,最后和4比较,故奇数位6位
1235 call一次 变成112 ,就是后者减去前者
如果第二次就是 01

最后覆盖后的结果(奇数是4位)必须满足:
第一位应该大于第二位
第二位应该小于第三位
第三位应该等于第四位

看懂所有算法后,我们就可以试着猜了
第一次肯定从0开始,011235 一次10112 再一次就不对了
继续猜~~从1开始,112358 依次01123 再一次 就是1011,刚好符合题意。运行下ok。搞定~~
然后注册码就是——121222325282

--------------------------------------------------------------------------------
【经验总结】
菜鸟第一次写破文,写得很乱,自己也不怎么会,只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
经验就是需要耐心吧,OD结合到IDA用效果会更好,对有些简单算法的反汇编代码应该熟悉。

--------------------------------------------------------------------------------
【版权声明】: 本文原创于JoyChou 转载请注明作者并保持文章的完整, 谢谢!

2012年06月09日 1:52:54

原文地址:https://www.cnblogs.com/Joy7/p/2542778.html