【文章标题】: 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,2,4,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