• 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

  • 相关阅读:
    miniui mini-combobox的使用
    xsd文件记录
    Hibernate 一次查询分多次返回 避免内存溢出
    卡口扩展信息
    删除 maven仓库,更新失败的jar包命令
    杀windows进程
    layer 遮罩层等待
    math() 对象
    JavaScript 字符串方法
    JavaScript 数组遍历方法;
  • 原文地址:https://www.cnblogs.com/Joy7/p/2542778.html
Copyright © 2020-2023  润新知