首页
社区
课程
招聘
OD复制BUG分析和修正
发表于: 2005-5-6 18:12 12823

OD复制BUG分析和修正

nbw 活跃值
24
2005-5-6 18:12
12823

OD复制BUG分析和修正

作者: nbw   
nbw.07cn.com
For NE365

使用OD,从内存区复制内存数据的时候,有时候无法将所有的数据都复制到剪贴板,应该是od一个bug,本文说以下该bug的产生原因和解决方法。最后给出一个处理补丁。
我这里处理的是 OllyDbg v1.0 2005.3 修正版。

用一个OD1附加另外一个OD2,在OD2里面复制内存区内容。

拦截剪贴板操作函数,到:

0044AE96         |.  53                push ebx                                      ; /hData
0044AE97         |.  6A 0D             push 0D                                       ; |Format = CF_UNICODETEXT
0044AE99         |.  E8 E4460600       call <jmp.&USER32.SetClipboardData>           ; \SetClipboardData

其中 push ebx传入数据缓冲区指针。
上面有函数处理最终输入剪贴板的数据:
0044AE6B         |.  52                push edx                                      ; /Arg3
0044AE6C         |.  50                push eax                                      ; |Arg2
0044AE6D         |.  8B45 0C           mov eax,dword ptr ss:[ebp+C]                  ; |
0044AE70         |.  50                push eax                                      ; |Arg1
0044AE71         |.  E8 A2B7FFFF       call OLLYDBG.00446618                         ; \OLLYDBG.00446618

上面的call OLLYDBG.00446618将用户需要复制的数据转换成Unicode编码,然后填入输出缓冲区,这是个循环,不能一次性转换完毕,需要一块一块进行。关键地方如下:
将复制的数据转换为UNICODE编码:

00446A1C         |> \68 00020000   ||push 200                                   ; /WideBufSize = 200 (512.)
00446A21         |.  8D95 78FAFFFF ||lea edx,dword ptr ss:[ebp-588]             ; |
00446A27         |.  52            ||push edx                                   ; |WideCharBuf
00446A28         |.  53            ||push ebx                                   ; |StringSize
00446A29         |.  8D8D 78FDFFFF ||lea ecx,dword ptr ss:[ebp-288]             ; |
00446A2F         |.  51            ||push ecx                                   ; |StringToMap
00446A30         |.  6A 01         ||push 1                                     ; |Options = MB_PRECOMPOSED
00446A32         |.  6A 00         ||push 0                                     ; |CodePage = CP_ACP
00446A34         |.  E8 1D870600   ||call <jmp.&KERNEL32.MultiByteToWideChar>   ; \MultiByteToWideChar

往缓冲区填充转换出来的UNICODE数据:

00446CA7         |.  50            ||push eax                                   ; /数据长度
00446CA8         |.  52            ||push edx                                   ; |原始数据地址
00446CA9         |.  8B4D D8       ||mov ecx,dword ptr ss:[ebp-28]              ; |
00446CAC         |.  03C9          ||add ecx,ecx                                ; |
00446CAE         |.  034D CC       ||add ecx,dword ptr ss:[ebp-34]              ; |
00446CB1         |.  51            ||push ecx                                   ; |缓冲区地址
00446CB2         |.  E8 79C80500   ||call OLLYDBG.004A3530                      ; \填充数据

填写每行后面的回车换行符号:
00446CFE         |.  66:C70441 0D0>|mov word ptr ds:[ecx+eax*2],0D              ;  填充换行符号
00446D04         |.  FF45 D8       |inc dword ptr ss:[ebp-28]
00446D07         |.  8B55 CC       |mov edx,dword ptr ss:[ebp-34]
00446D0A         |.  8B4D D8       |mov ecx,dword ptr ss:[ebp-28]
00446D0D         |.  66:C7044A 0A0>|mov word ptr ds:[edx+ecx*2],0A              ;  填写回车符号

上面的 MultiByteToWideChar 是关键地方。这个函数有时候转换出来的数据中会存在连续2个字节的00。

比如现在要从内存模块复制以下2行数据:

004029F0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 CC  ...............
00402A00  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

以上数据转换成的unicode编码如下:

005F2320   30 00 30 00 34 00 30 00 32 00 39 00 46 00 30 00  0.0.4.0.2.9.F.0.
005F2330   20 00 20 00 30 00 30 00 20 00 30 00 30 00 20 00   . .0.0. .0.0. .
005F2340   30 00 30 00 20 00 30 00 30 00 20 00 30 00 30 00  0.0. .0.0. .0.0.
005F2350   20 00 30 00 30 00 20 00 30 00 30 00 20 00 30 00   .0.0. .0.0. .0.
005F2360   30 00 20 00 30 00 30 00 20 00 30 00 30 00 20 00  0. .0.0. .0.0. .
005F2370   30 00 30 00 20 00 30 00 30 00 20 00 30 00 30 00  0.0. .0.0. .0.0.
005F2380   20 00 30 00 30 00 20 00 30 00 30 00 20 00 43 00   .0.0. .0.0. .C.
005F2390   43 00 20 00 20 00 2E 00 2E 00 2E 00 2E 00 2E 00  C. . ...........
005F23A0   2E 00 2E 00 2E 00 2E 00 2E 00 2E 00 2E 00 2E 00  ................
005F23B0   2E 00 2E 00 00 00 0D 00 0A 00 30 00 30 00 34 00  ..........0.0.4.
005F23C0   30 00 32 00 41 00 30 00 30 00 20 00 20 00 30 00  0.2.A.0.0. . .0.
005F23D0   30 00 20 00 30 00 30 00 20 00 30 00 30 00 20 00  0. .0.0. .0.0. .
005F23E0   30 00 30 00 20 00 30 00 30 00 20 00 30 00 30 00  0.0. .0.0. .0.0.
005F23F0   20 00 30 00 30 00 20 00 30 00 30 00 20 00 30 00   .0.0. .0.0. .0.
005F2400   30 00 20 00 30 00 30 00 20 00 30 00 30 00 20 00  0. .0.0. .0.0. .
005F2410   30 00 30 00 20 00 30 00 30 00 20 00 30 00 30 00  0.0. .0.0. .0.0.
005F2420   20 00 30 00 30 00 20 00 30 00 30 00 20 00 20 00   .0.0. .0.0. . .
005F2430   2E 00 2E 00 2E 00 2E 00 2E 00 2E 00 2E 00 2E 00  ................
005F2440   2E 00 2E 00 2E 00 2E 00 2E 00 2E 00 2E 00 2E 00  ................
005F2450   0D 00 0A 00 0D 00 0A 00 00 00 00 00 00 00 00 00  ................

可以看到005F23B0那行:
005F23B0   2E 00 2E 00 00 00 0D 00 0A 00 30 00 30 00 34 00  ..........0.0.4.

前面的 2E 00 2E 00 是第一行倒数第2个和倒数第3个数据,也就是被004029F0那行最后的2个小数点,而2E 00后面的连续2个00就是因为要复制的数据CC被OD转换成的字符无法被转换成Unicode而留下来的,再往后0D 00 0A 00 是回车换行。
看起来有点混乱,主要是我表达不太清楚。
换句话说,要复制的数据:
004029F0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 CC  ...............@
左边的数据被OD在右边显示成相应的ASCII码,CC被显示成一个字符而不是小数点,假定是 @ ,当然实际上不是,你可以去OD看一下。然后复制的时候,那个@也被包含了进去,但是转换unicode码的时候被转换成了连续的2个00。

因为剪贴板操作数据仅仅根据的缓冲区句柄,是数据中间出现了2个00,从而导致使00后面的数据被视而不见。
有很多办法可以处理这个问题,我这里修正MultiByteToWideChar的输出数据。

修正MultiByteToWideChar函数

该函数将输入的字符串转换为Unicode编码。如果输入的数据中含有大于0x80的字节,可能会导致输出数据的最后2个字节都为00,从而截断需要复制的数据。

分析:

    名称     RVA     OA        尺寸D   可写否
   .text  000b0000  000af600  -2048      否
   .data  0010b000  00109e00  -253440      可
    .tls  0010c000  000cd000  -3584      可
  .rdata  0010d000  000cd200  -3584      否
  .idata  0010f000  000ce400   -512      否
  .edata  00111000  000d0200  -3072      否
   .rsrc  00145934  00103f34    212      否
  .reloc  00152000  00110200   -512      否
有效剩余空间(字节D)为: 212

选定  .rsrc 段 00145954 处
即:
00545954   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00545964   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

函数调用如下:

;ecx -> 输入缓冲区
;edx -> 输出缓冲区
;ebx -> 数据长度

00446A1C         |> \68 00020000       ||push 200                                    ; /WideBufSize = 200 (512.)
00446A21         |.  8D95 78FAFFFF     ||lea edx,dword ptr ss:[ebp-588]              ; |
00446A27         |.  52                ||push edx                                    ; |WideCharBuf
00446A28         |.  53                ||push ebx                                    ; |StringSize
00446A29         |.  8D8D 78FDFFFF     ||lea ecx,dword ptr ss:[ebp-288]              ; |
00446A2F         |.  51                ||push ecx                                    ; |StringToMap
00446A30         |.  6A 01             ||push 1                                      ; |Options = MB_PRECOMPOSED
00446A32         |.  6A 00             ||push 0                                      ; |CodePage = CP_ACP
00446A34         |.  E8 1D870600       ||call <jmp.&KERNEL32.MultiByteToWideChar>    ; \MultiByteToWideChar
                                                                                     ;:00446A34 E81D870600      Call 004AF156
00446A39         |.  8BD8              ||mov ebx,eax

下面进行修正:

00446A1C         |> \68 00020000       ||push 200
修改为 jmp 00545954

在00545954处添加代码:

    lea edx,dword ptr ss:[ebp-588]              ; |
    lea ecx,dword ptr ss:[ebp-288]              ; |
    push ecx                                    ;保存输入缓冲区地址
    push edx                                    ;保存输出缓冲区地址

    push 200                                    ; /WideBufSize = 200 (512.)
    push edx                                    ; |WideCharBuf
    push ebx                                    ; |StringSize
    push ecx                                    ; |StringToMap
    push 1                                      ; |Options = MB_PRECOMPOSED
    push 0                                      ; |CodePage = CP_ACP
    call <jmp.&KERNEL32.MultiByteToWideChar>    ; \MultiByteToWideChar

    pop edx                                     ;输出缓冲区
    pop ecx                                     ;输入缓冲区
    mov ebx, eax                                ;获取输出缓冲区长度,这里采用上面API函数返回值不采用原来的输入长度,因为有时候不一样

    add   ebx, ebx
    add   edx, ebx
    sub   edx, 2                                ;定位到输出缓冲区倒数第2个字节
    movzx ebx, word ptr [edx]
    cmp   ebx , 0
    je    @F
    jmp   00446A39                              ;返回
@@:
    mov   byte ptr[edx], 01                     ;如果最后是连续2个00字节,那么写入01,正确性不管了,如果愿意你可以自己修正 :)
    jmp   00446A39

关于MultiByteToWideChar产生连续2个字节的00情况,是因为该函数计算数据的unicode码主要是根据查表,如果数据小于0x80,那么就不会产生连续2个字节的00,如果大于0x80,会导致数据前移,使得最后2个字节是00,如果再大(具体多少没研究),就不会有00了,不过产生的数据应该不对。有兴趣的朋友可以看看这个函数,并不复杂。
按道理网上或者什么地方应该有关于这个情况的解释,哪位晓得不妨给我说以下。

修改完毕,对同一段内存,测试以下。

修改前的可以复制:
00402230  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 56  ...............V
00402240  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 66  ...............f
00402250  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78  ...............x
00402260  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 88  ...............

修改后的版本可以复制:
00402250  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 56  ...............V
00402260  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 66  ...............f
00402270  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78  ...............x
00402280  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 88  ...............
00402290  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 98  ...............
004022A0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F8  ...............
004022B0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

我不太敢改调试器之类的东西,怕出了问题影响大家工作,所以如果发现问题请给我说以下,我好改正。

多谢!

附件:ODpatch.rar


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (15)
雪    币: 296
活跃值: (260)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
2
坐一下沙发,去学校了,下次回来试~
辛苦了~~~
2005-5-6 18:15
0
雪    币: 110
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2005-5-6 18:19
0
雪    币: 258
活跃值: (230)
能力值: ( LV12,RANK:770 )
在线值:
发帖
回帖
粉丝
4
od多次转储保存文件,,,,,时候会提示警告的...
还必须改下旧的文件,,,,看来这次牛哥把bug剔除,,,,支持...
2005-5-6 19:01
0
雪    币: 238
活跃值: (250)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
5
支持!
2005-5-6 20:21
0
雪    币: 204
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
不错。希望楼主有时间把od多方位分析一下。

不知3月几号的版本,我的3.5校验错。
2005-5-7 09:14
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
7
3月3日的版本。不是那个xp界面的。我就怕版本会有问题,专门挑了个觉得比较晚的,没想到还是没挑对。
2005-5-7 11:33
0
雪    币: 151
活跃值: (66)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
8
好久没看到你的精华帖了。
2005-5-7 11:58
0
雪    币: 332
活跃值: (479)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
9
支持,NBW老弟。
2005-5-7 12:30
0
雪    币: 234
活跃值: (104)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
厉害厉害!
2005-5-7 21:31
0
雪    币: 389
活跃值: (912)
能力值: ( LV9,RANK:770 )
在线值:
发帖
回帖
粉丝
11
OllyDbg复制补丁

适用: OllyDbg v1.0 2005.3 修正版

制作: [nbw]
nbw.07cn.com

使用OD,从内存区复制内存数据的时候,有时候无法将所有的数据都复制到剪贴板,本补丁修正该问题。

有bug请告诉我!

多谢!

检查补丁能否应用于当前目录或指定的目录.............成功!

打开文件 OLLYDBG.EXE..............成功!
进行 CRC32 校验......................失败!
2005-5-8 16:18
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
12
看来版本搞错了,我这里的od不是最近发布的那个有xp界面的,这几天忙完了我再做个。
不过把那个ASCII码显示给屏蔽掉就可以不受这个bug的影响,我也是刚听fly说的。
2005-5-8 21:32
0
雪    币: 124
活跃值: (70)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
00545954    90              NOP
00545955    90              NOP
00545956    90              NOP
00545957    90              NOP
00545958    90              NOP
00545959    90              NOP
0054595A    90              NOP
0054595B    90              NOP
0054595C    8D95 78FAFFFF   LEA EDX,DWORD PTR SS:[EBP-588]
00545962    8D8D 78FDFFFF   LEA ECX,DWORD PTR SS:[EBP-288]
00545968    51              PUSH ECX
00545969    52              PUSH EDX
0054596A    90              NOP
0054596B    90              NOP
0054596C    90              NOP
0054596D    90              NOP
0054596E    90              NOP
0054596F    90              NOP
00545970    68 0002003E     PUSH 3E000200
00545975    52              PUSH EDX
00545976    53              PUSH EBX
00545977    51              PUSH ECX
00545978    6A 01           PUSH 1
0054597A    6A 00           PUSH 0
0054597C    E8 D597F6FF     CALL 004AF156
00545981    90              NOP
00545982    90              NOP
00545983    8BD8            MOV EBX,EAX
00545985    90              NOP
00545986    90              NOP
00545987    5A              POP EDX
00545988    59              POP ECX
00545989    03DB            ADD EBX,EBX
0054598B    03D3            ADD EDX,EBX
0054598D    83EA 02         SUB EDX,2
00545990    0FB71A          MOVZX EBX,WORD PTR DS:[EDX]
00545993    83FB 00         CMP EBX,0
00545996    90              NOP
00545997    74 05           JE SHORT 0054599E
00545999  - E9 9B10F0FF     JMP 00446A39
0054599E    90              NOP
0054599F    90              NOP
005459A0    90              NOP
005459A1    C602 01         MOV BYTE PTR DS:[EDX],1
005459A4  - E9 9010F0FF     JMP 00446A39

这些nop是从那里来的?我去掉nop后

00446A2A   /EB 1F           JMP SHORT 00446A4B
00446A2C   |E9 3F8C0600     JMP 004AF670
00446A31   |8D95 78FAFFFF   LEA EDX,DWORD PTR SS:[EBP-588]
00446A37   |52              PUSH EDX
00446A38   |53              PUSH EBX
00446A39   |8D8D 78FDFFFF   LEA ECX,DWORD PTR SS:[EBP-288]
00446A3F   |51              PUSH ECX
00446A40   |6A 01           PUSH 1
00446A42   |6A 00           PUSH 0
00446A44   |E8 05870600     CALL <JMP.&KERNEL32.MultiByteToWideChar>
00446A49   |8BD8            MOV EBX,EAX
00446A4B   \F645 E4 80      TEST BYTE PTR SS:[EBP-1C],80

004AF670    8D95 78FAFFFF   LEA EDX,DWORD PTR SS:[EBP-588]
004AF676    8D8D 78FDFFFF   LEA ECX,DWORD PTR SS:[EBP-288]
004AF67C    51              PUSH ECX
004AF67D    52              PUSH EDX
004AF67E    68 00020000     PUSH 200
004AF683    52              PUSH EDX
004AF684    53              PUSH EBX
004AF685    51              PUSH ECX
004AF686    6A 01           PUSH 1
004AF688    6A 00           PUSH 0
004AF68A    E8 BFFAFFFF     CALL <JMP.&KERNEL32.MultiByteToWideChar>
004AF68F    5A              POP EDX
004AF690    59              POP ECX
004AF691    8BD8            MOV EBX,EAX
004AF693    03DB            ADD EBX,EBX
004AF695    03D3            ADD EDX,EBX
004AF697    83EA 02         SUB EDX,2
004AF69A    0FB71A          MOVZX EBX,WORD PTR DS:[EDX]
004AF69D    83FB 00         CMP EBX,0
004AF6A0    74 05           JE SHORT 004AF6A7
004AF6A2  ^ E9 A273F9FF     JMP 00446A49
004AF6A7    C602 01         MOV BYTE PTR DS:[EDX],1
004AF6AA  ^ E9 9A73F9FF     JMP 00446A49

附上bin数据

8D 95 78 FA FF FF 8D 8D 78 FD FF FF 51 52 68 00 02 00 00 52 53 51 6A 01 6A 00 E8 BF FA FF FF 5A
59 8B D8 03 DB 03 D3 83 EA 02 0F B7 1A 83 FB 00 74 05 E9 A2 73 F9 FF C6 02 01 E9 9A 73 F9 FF 00

我是手动修补的,顺便再贴上“OutputDebugString”格式化字符串漏洞的修复代码

00431342    52              PUSH EDX
00431343    E8 D4FF0200     CALL _Readmemory
00431348    E9 F3E20700     JMP 004AF640
0043134D    74 0A           JE SHORT 00431359
0043134F    B8 01000000     MOV EAX,1

004AF640    51              PUSH ECX
004AF641    50              PUSH EAX
004AF642    57              PUSH EDI
004AF643    8B7C24 0C       MOV EDI,DWORD PTR SS:[ESP+C]
004AF647    8B4C24 14       MOV ECX,DWORD PTR SS:[ESP+14]
004AF64B    B8 25000000     MOV EAX,25
004AF650    F2:AE           REPNE SCAS BYTE PTR ES:[EDI]
004AF652    83F9 00         CMP ECX,0
004AF655    74 06           JE SHORT 004AF65D
004AF657    C647 FF 20      MOV BYTE PTR DS:[EDI-1],20
004AF65B  ^ EB F3           JMP SHORT 004AF650
004AF65D    5F              POP EDI
004AF65E    58              POP EAX
004AF65F    59              POP ECX
004AF660    83C4 10         ADD ESP,10
004AF663    3BC3            CMP EAX,EBX
004AF665  ^ E9 E31CF8FF     JMP 0043134D

bin
51 50 57 8B 7C 24 0C 8B 4C 24 14 B8 25 00 00 00 F2 AE 83 F9 00 74 06 C6 47 FF 20 EB F3 5F 58 59
83 C4 10 3B C3 E9 E3 1C F8 FF
2005-5-8 22:34
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
14
那些nop是我做的时候添加的,因为修改代码的时候未必能一次修改成功,很多时候中间需要修改1、2句,然后我最开始就在里面插入很多nop,便于后来修改不正确的代码。

那个OutputDebugString不错,学习!
2005-5-8 22:43
0
雪    币: 124
活跃值: (70)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
15
修改了下你的代码,短了点。。

00446A44    E8 05870600       CALL <JMP.&KERNEL32.MultiByteToWideChar>
00446A49    E9 228C0600       JMP 004AF670
00446A4E    90                NOP
00446A4F    0F84 2C010000     JE 00446B81

004AF670    8D95 78FAFFFF     LEA EDX,DWORD PTR SS:[EBP-588]
004AF676    8BD8              MOV EBX,EAX
004AF678    03DB              ADD EBX,EBX
004AF67A    03D3              ADD EDX,EBX
004AF67C    83EA 02           SUB EDX,2
004AF67F    0FB71A            MOVZX EBX,WORD PTR DS:[EDX]
004AF682    83FB 00           CMP EBX,0
004AF685    75 03             JNZ SHORT 004AF68A
004AF687    C602 01           MOV BYTE PTR DS:[EDX],1
004AF68A    8BD8              MOV EBX,EAX
004AF68C    F645 E4 80        TEST BYTE PTR SS:[EBP-1C],80
004AF690  ^ E9 BA73F9FF       JMP 00446A4F

bin
8D 95 78 FA FF FF 8B D8 03 DB 03 D3 83 EA 02 0F B7 1A 83 FB 00 75 03 C6 02 01 8B D8 F6 45 E4 80
E9 BA 73 F9 FF
2005-5-8 23:38
0
雪    币: 538
活跃值: (32)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
在学校只能学习了,回家下
2005-5-11 12:44
0
游客
登录 | 注册 方可回帖
返回
//