首页
社区
课程
招聘
[原创]OD 写补丁代码插件 SkyPatch 的 bug 修正
发表于: 2009-5-2 14:25 17784

[原创]OD 写补丁代码插件 SkyPatch 的 bug 修正

2009-5-2 14:25
17784

【文章标题】: OD 写补丁代码插件 SkyPatch 的 bug 修正
【文章作者】: CCDebuger
【软件名称】: SkyPatch 1.1
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  SkyPatch 插件用来在 OD 中写补丁代码是比较方便的。不过这个插件有个 bug,就是当写入的字串放在 VA 地址 00A00000 以后,则无法构建。如果构建的话,则会出现类似这样的错误:
  
  错误的命令位于行: 18 PUSH a17250 Unknown identifier
  构建失败
  
  补丁代码类似于这样:
  
  @0x00A17250:
  $str1 "xxxxxx"
  
  以下代码省略...
  
  PUSH $str1
  
  这里要在 OD 中正常汇编的话,转换后的指令应该是:
  
  PUSH 0a17250
  
  这样才能正常编译。可见 SkyPatch 插件在把地址的 DWORD 值转换为字串时,把前面的 0 丢掉了。如果地址是低于 00A00000 的值,这样没什么问题,但如果转换的字串地址大于 00A00000,则无法编译了。现在试着修复这个错误。用 IDA 分析一下 SkyPatch 插件,根据出错字串“错误的命令位于行”很容易发现有三个地方调用。两个地方都是调用 OD 的汇编功能的,不是我们要找的地方。那就只有这个地方:
  
  .text:1000F1DF loc_1000F1DF:                           ; CODE XREF: _Convert_Param_to_Str+EFj
  .text:1000F1DF                 mov     edx, [eax+0Ch]
  .text:1000F1E2                 mov     ecx, (offset LibFileName+124h)
  .text:1000F1E7                 and     dh, 0F9h
  .text:1000F1EA                 or      dh, 8
  .text:1000F1ED                 mov     [eax+0Ch], edx
  .text:1000F1F0                 mov     eax, [esp+3Ch+arg_0]
  .text:1000F1F4                 push    eax             ; 这里就是地址的DWORD值
  .text:1000F1F5                 call    ds:std::basic_ostream<char,std::char_traits<char>>::operator<<(uint)
  .text:1000F1F5
  .text:1000F1FB                 lea     ecx, [esp+3Ch+var_1C]
  .text:1000F1FF                 push    ecx
  .text:1000F200                 mov     ecx, (offset LibFileName+11Ch)
  .text:1000F205                 call    ds:std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>>::str(void)
  .text:1000F205
  .text:1000F20B                 mov     esieax
  .text:1000F20D                 mov     edxds:uint const std::basic_string<char,std::char_traits<char>,std::allocator<char>>::npos
  .text:1000F213                 mov     ecx, [esi+8]
  .text:1000F216                 mov     [esp+3Ch+var_4], 1
  .text:1000F21E                 mov     eax, [edx]
  .text:1000F220                 mov     edieax
  .text:1000F222                 cmp     ecxedi
  .text:1000F224                 jnb     short loc_1000F228
  .text:1000F224
  .text:1000F226                 mov     ediecx        ; 在 EDI 中保留转换后的地址字串长度值
  .text:1000F226
  .text:1000F228
  .text:1000F228 loc_1000F228:                           ; CODE XREF: _Convert_Param_to_Str+144j
  .text:1000F228                 sub     eax, [ebp+8]
  .text:1000F22B                 cmp     eaxedi
  .text:1000F22D                 ja      short loc_1000F235
  .text:1000F22D
  .text:1000F22F                 call    ds:std::_Xlen(void)
  .text:1000F22F
  .text:1000F235
  .text:1000F235 loc_1000F235:                           ; CODE XREF: _Convert_Param_to_Str+14Dj
  .text:1000F235                 test    ediedi
  .text:1000F237                 jbe     short loc_1000F27C
  .text:1000F237
  .text:1000F239                 mov     ebx, [ebp+8]
  .text:1000F23C                 push    0
  .text:1000F23E                 add     ebxedi        ; 地址字串长度或指令+地址字串长度送到 EBX
  .text:1000F240                 mov     ecxebp
  .text:1000F242                 push    ebx
  .text:1000F243                 call    ds:std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Grow(uint,bool)
  .text:1000F243
  .text:1000F249                 test    alal
  .text:1000F24B                 jz      short loc_1000F27C
  .text:1000F24B
  .text:1000F24D                 mov     esi, [esi+4]    ; [ESI+4]中就是转换后的地址字串
  .text:1000F250                 test    esiesi
  .text:1000F252                 jnz     short loc_1000F25A
  .text:1000F252
  .text:1000F254                 mov     esids:char const `std::basic_string<char,std::char_traits<char>,std::allocator<char>>::_Nullstr(void)'::`2'::_C
  .text:1000F254
  .text:1000F25A
  .text:1000F25A loc_1000F25A:                           ; CODE XREF: _Convert_Param_to_Str+172j
  .text:1000F25A                 mov     eax, [ebp+4]
  .text:1000F25D                 mov     ecxedi
  .text:1000F25F                 mov     edi, [ebp+8]
  .text:1000F262                 add     edieax
  .text:1000F264                 mov     eaxecx
  ----------------------------------------------------------------------------------------------------------
  现在复制一个原版的 OllyDBG,只配置 SkyPatch 这一个插件,这个新配置的 OD 我们设为 OD1。现在用我们自己常用的 OD 打开 OD1,用 OD1 载入我们要打补丁的程序,调用 SkyPatch 打开要写入的补丁脚本。现在转到我们自己常用的 OD 中,ALT+E 打开模块窗口,双击 SkyPatch 模块,在汇编窗口中定位到我们上面看到的代码处,设断点。当然上面的代码是我已经结合 OD 分析过的,第一次我们可能定位的位置并不一定对。不过没关系,可以根据断下来后程序的执行情况再调整断点。这个各位可以自己测试。现在说一下在 OD 中调试看到的情况:
  
  026AF1F4  |.  50            PUSH EAX                                         ;  EAX 就是参数经过转换后所得到的地址 DWORD 值
  026AF1F5  |.  FF15 60306B02 CALL DWORD PTR DS:[<&MSVCP60.??6?$basic_ostream@>;  MSVCP60.??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@I@Z
  026AF1FB  |.  8D4C24 20     LEA ECX,DWORD PTR SS:[ESP+20]
  026AF1FF  |.  51            PUSH ECX
  026AF200  |.  B9 807C6B02   MOV ECX,026B7C80
  026AF205  |.  FF15 F8306B02 CALL DWORD PTR DS:[<&MSVCP60.?str@?$basic_string>;  MSVCP60.?str@?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ
  026AF20B  |.  8BF0          MOV ESI,EAX
  026AF20D  |.  8B15 BC306B02 MOV EDX,DWORD PTR DS:[<&MSVCP60.?npos@?$basic_st>;  MSVCP60.?npos@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@2IB
  026AF213  |.  8B4E 08       MOV ECX,DWORD PTR DS:[ESI+8]                     ;  转换后的地址字串长度
  026AF216  |.  C74424 38 010>MOV DWORD PTR SS:[ESP+38],1
  026AF21E  |.  8B02          MOV EAX,DWORD PTR DS:[EDX]
  026AF220  |.  8BF8          MOV EDI,EAX
  026AF222  |.  3BCF          CMP ECX,EDI                                      ;  比较字串长度是否大于等于0
  026AF224  |.  73 02         JNB SHORT 026AF228
  026AF226  |.  8BF9          MOV EDI,ECX                                      ;  在 EDI 中保留转换后的地址字串长度值
  026AF228      2B45 08       SUB EAX,DWORD PTR SS:[EBP+8]
  026AF22B      3BC7          CMP EAX,EDI
  026AF22D  |.  77 06         JA SHORT 026AF235
  026AF22F  |.  FF15 CC306B02 CALL DWORD PTR DS:[<&MSVCP60.?_Xlen@std@@YAXXZ>] ;  MSVCP60.?_Xlen@std@@YAXXZ
  026AF235  |>  85FF          TEST EDI,EDI                                     ;  判断字串长度是否等于0
  026AF237  |.  76 43         JBE SHORT 026AF27C
  026AF239  |.  8B5D 08       MOV EBX,DWORD PTR SS:[EBP+8]
  026AF23C  |.  6A 00         PUSH 0
  026AF23E  |.  03DF          ADD EBX,EDI                                      ;  地址字串长度或指令+地址字串长度送到 EBX
  026AF240  |.  8BCD          MOV ECX,EBP
  026AF242  |.  53            PUSH EBX
  026AF243  |.  FF15 C0306B02 CALL DWORD PTR DS:[<&MSVCP60.?_Grow@?$basic_stri>;  MSVCP60.?_Grow@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AAE_NI_N@Z
  026AF249  |.  84C0          TEST AL,AL
  026AF24B  |.  74 2F         JE SHORT 026AF27C
  026AF24D      8B76 04       MOV ESI,DWORD PTR DS:[ESI+4]                     ;  [ESI+4]中就是转换后的地址字串
  026AF250      85F6          TEST ESI,ESI
  026AF252  |.  75 06         JNZ SHORT 026AF25A
  026AF254  |.  8B35 1C316B02 MOV ESI,DWORD PTR DS:[<&MSVCP60.?_C@?1??_Nullstr>;  MSVCP60.?_C@?1??_Nullstr@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@CAPBDXZ@4DB
  026AF25A      8B45 04       MOV EAX,DWORD PTR SS:[EBP+4]                     ;  这里改成跳到我们的补丁代码处执行
  026AF25D      8BCF          MOV ECX,EDI
  026AF25F  |.  8B7D 08       MOV EDI,DWORD PTR SS:[EBP+8]
  026AF262  |.  03F8          ADD EDI,EAX
  026AF264  |.  8BC1          MOV EAX,ECX
  026AF266  |.  C1E9 02       SHR ECX,2
  026AF269  |.  F3:A5         REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
  026AF26B  |.  8BC8          MOV ECX,EAX
  026AF26D  |.  83E1 03       AND ECX,3
  026AF270  |.  F3:A4         REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
  ----------------------------------------------------------------------------------------------------------
  从上面可以看出,程序是调用了 STL 模板库中的标准函数把地址的 DWORD 转成了字串,不过后面没对转换后字串的第一个字符是否位于“a”到“f”间作判断,就直接拿来用了。导致会出现我们开始时提到的那个错误。现在我们只要加上这个判断,如果第一个字符在“a”到“f”之间,我们就在字串前面插一个“0”字符。这里就偷个懒,直接判断第一个字符是否大于字符“9”,如果大于则在字串前面插一个“0”字符。找一个空白地方写我们的代码,我这把补丁代码放在 RVA 125C0 处。根据程序在我这重定位后的基址,我在 VA 026B25C0 处写补丁代码。先把上面地址 026AF25A 处的代码改为跳到我们的补丁代码处执行:
  ----------------------------------------------------------------------------------------------------------
  修改后代码:
  026AF25A      E9 61330000   JMP 026B25C0                                     ;  这里改成跳到我们的补丁代码处执行
  026AF25F  |.  8B7D 08       MOV EDI,DWORD PTR SS:[EBP+8]
  ----------------------------------------------------------------------------------------------------------
  要写的补丁代码:
  026B25C0      60            PUSHAD                                           ;  保护现场
  026B25C1      9C            PUSHFD
  026B25C2      803E 39       CMP BYTE PTR DS:[ESI],39                         ;  第一个字符是否大于9
  026B25C5      7F 0C         JG SHORT 026B25D3                                ;  大于9则处理,否则返回
  026B25C7      9D            POPFD
  026B25C8      61            POPAD
  026B25C9      8B45 04       MOV EAX,DWORD PTR SS:[EBP+4]
  026B25CC      8BCF          MOV ECX,EDI
  026B25CE    ^ E9 8CCCFFFF   JMP 026AF25F
  026B25D3      C6443E 01 00  MOV BYTE PTR DS:[ESI+EDI+1],0                    ;  地址字串最后面添加一个0字节
  026B25D8      8A443E FF     MOV AL,BYTE PTR DS:[ESI+EDI-1]
  026B25DC      88043E        MOV BYTE PTR DS:[ESI+EDI],AL                     ;  这里依次把地址字串的字符向后移一位,以便我们在字串开始的地方插一个0
  026B25DF      4F            DEC EDI
  026B25E0      83FF 00       CMP EDI,0                                        ;  判断字串是否都已移完
  026B25E3    ^ 75 F3         JNZ SHORT 026B25D8
  026B25E5      C606 30       MOV BYTE PTR DS:[ESI],30                         ;  在地址字串前面加一个字符0
  026B25E8      9D            POPFD
  026B25E9      61            POPAD
  026B25EA      43            INC EBX                                          ;  指令字串总长度加1
  026B25EB      47            INC EDI                                          ;  地址字串长度加1
  026B25EC      8B45 04       MOV EAX,DWORD PTR SS:[EBP+4]                     ;  恢复原始代码并返回继续执行
  026B25EF      8BCF          MOV ECX,EDI
  026B25F1    ^ E9 69CCFFFF   JMP 026AF25F                                     ;  返回到原程序的下一句代码继续执行
  
  附件是 dup 制作的补丁,可以直接对 SkyPatch 1.1 进行 patch 修正 bug。
  
--------------------------------------------------------------------------------
【版权声明】: 本文纯属技术交流, 转载请注明作者并保持文章的完整, 谢谢!


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (25)
雪    币: 7309
活跃值: (3788)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
2
其实,这个是OD的BUG。。。
2009-5-2 17:28
0
雪    币: 82
活跃值: (10)
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
3
sprintf %09x
2009-5-2 17:49
0
雪    币: 2110
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
4
其实,直接在前边加个0也没关系吧,不用判断,OD的汇编器只认十六进制数。
2009-5-2 18:43
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
我没细看,应该不需要修改任何代码,只修改某处一字符串就搞定。
2009-5-2 18:58
0
雪    币: 8183
活跃值: (3336)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
提供个原版吧,网上只找到1.0版本的
2009-5-4 22:40
0
雪    币: 51
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
我是新手  来学习下
2009-5-5 09:42
0
雪    币: 2506
活跃值: (1025)
能力值: (RANK:990 )
在线值:
发帖
回帖
粉丝
8
附加包含原版及我以前汉化的版本,也包括上面那个补丁。
上传的附件:
2009-5-5 12:16
0
雪    币: 101
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
支持,下载了。。。
2009-5-5 19:17
0
雪    币: 205
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
非常感谢,正需要。
2009-5-5 20:18
0
雪    币: 8183
活跃值: (3336)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
多谢CCDebuger大哥,下载试用去了
2009-5-9 09:02
0
雪    币: 319
活跃值: (2439)
能力值: ( LV12,RANK:980 )
在线值:
发帖
回帖
粉丝
12
补丁好象还不完整,有跳转时还会提示未知标识符错误。
如:错误的跳转命令位于行:47 je @L001 je c99f3e 未知标识符
2009-5-25 08:43
0
雪    币: 2401
活跃值: (1402)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
je c99f3e 未知标识符, 因為 c99f3e 被 OD 識別成 Label 而不是地址.
最簡單的解決方法, 不管第一位是 0-9 或 a-f, 一律都在最前前補 0.
就算是地址變成 9 位數的 00c99f3e , 我記得 OD 會自動修正成 8 位.
2009-5-25 10:21
0
雪    币: 97697
活跃值: (200759)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
14
Thanks for share.
2009-5-25 10:33
0
雪    币: 319
活跃值: (2439)
能力值: ( LV12,RANK:980 )
在线值:
发帖
回帖
粉丝
15
CCDebuger大大的补丁还有一个跳转BUG未修复,完善了一下,完全是CCDebuger的版权
上传的附件:
2009-5-25 21:12
0
雪    币: 191
活跃值: (345)
能力值: ( LV9,RANK:450 )
在线值:
发帖
回帖
粉丝
16
NonaWrite 1.2 好像比 SkyPatch 好用点吧,不过也有写入地址为 xxxx 反正是当地址为字母开头的就会出错,比如 A00000

CCDebuger 有空也看一下 NonaWrite 1.2  吧。记得论坛上有插件原码的。可以直接重新编译
2009-5-25 21:58
0
雪    币: 191
活跃值: (345)
能力值: ( LV9,RANK:450 )
在线值:
发帖
回帖
粉丝
17
压缩包中集合了1楼和15楼的修改做的补丁,包括中英文原版。

这个补丁本打算自己用来着,后来在网上终于找到了英文原版,所以大家别在意补丁中的版权了,版权归1楼和15楼所有吧。
上传的附件:
2009-5-25 22:17
0
雪    币: 58
活跃值: (23)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
又见海风月影就想起象棋奇兵
2009-5-25 22:48
0
雪    币: 427
活跃值: (65)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
19
象棋奇兵?风月破解的?
2009-5-25 23:23
0
雪    币: 2506
活跃值: (1025)
能力值: (RANK:990 )
在线值:
发帖
回帖
粉丝
20
不能这么说,你能让它更完善,是你的功劳。

NonaWrite 没源码吧?好像没看到过。
2009-5-25 23:59
0
雪    币: 191
活跃值: (345)
能力值: ( LV9,RANK:450 )
在线值:
发帖
回帖
粉丝
21
这个插件好像是没有
2009-5-26 03:00
0
雪    币: 1436
活跃值: (3861)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
22
SkyPatch处理mov的时候还有一个bug,sky patch将MOV EDX,64翻译成
004F223A      C7C2 64000000             MOV EDX,64
;但od将其翻译成
004F223A      BA 64000000               MOV EDX,64
以上两个代码执行都没问题,但是如果只需补丁MOV EDX,64成MOV EDX,63,直接用sky patch补丁就会出错,将把补丁位置后面的代码给覆盖了。
2009-6-13 16:51
0
雪    币: 370
活跃值: (15)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
23
fixbug更新了,刚看到
2009-6-13 18:16
0
雪    币: 116
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
24
为什么这个插件会出现异常然后崩溃呢?是我的OD版本有问题吗?我可是从看雪网站上下的版本啊
2009-6-13 21:41
0
雪    币: 1436
活跃值: (3861)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
25
作者更新了,这个问题没有了
http://www.unpack.cn/viewthread.php?tid=37707
2009-7-4 19:17
0
游客
登录 | 注册 方可回帖
返回
//