📄 chap6-1-41.htm.primary
字号:
push 00000000 <br>
:0040172B 6848344000
push 00403448 <br>
:00401730 6A12
push 00000012 <br>
:00401732 68E8344000
push 004034E8 <br>
:00401737 FF3544344000 push
dword ptr [00403444] <br>
<br>
* Reference To: KERNEL32.ReadFile, Ord:01FDh <br>
| <br>
:0040173D E8D0000000
Call 00401812
;第三次读取数据,长度为0x12(18) <br>
:00401742 E882F9FFFF
call 004010C9
;关键所在!!!F8进去 <br>
<br>
<br>
在SoftICe中下断点bpx readfile,可以来到上面的位置,除了文件读取ReadFile是否成功的必要检查之外,基本上没有什么跳转,而且call也不多,这使我感到非常幸运。首先F8到00401724处的call
00401000,来到下面的地方: <br>
<br>
:00401000 33C0
xor eax, eax <br>
:00401002 33D2
xor edx, edx <br>
:00401004 33C9
xor ecx, ecx <br>
:00401006 8A0DFA344000 mov
cl, byte ptr [004034FA] ;还记得这个值吗,看看上面,就是文件第一个字节的值
<br>
:0040100C BE88324000
mov esi, 00403288 ;在上面看看,是第二次读取数据的缓冲区
<br>
:00401011 AC
lodsb
;读取缓冲区内容到AL中 <br>
:00401012 03D0
add edx, eax
;将AL加到EDX中 <br>
:00401014 E2FB
loop 00401011
;不断重复,结果是将第二次所有数据累加起来 <br>
:00401016 8815FB344000 mov
byte ptr [004034FB], dl ;放到[004034FB],注意,以后要用的
<br>
:0040101C C3
ret <br>
<br>
<br>
继续跟踪第二个call,即00401742处的call 004010C9,如下: <br>
<br>
:004010C9 55
push ebp <br>
:004010CA 8BEC
mov ebp, esp <br>
:004010CC 83C4FC
add esp, FFFFFFFC <br>
<br>
* Possible StringData Ref from Data Obj ->"****************C*......*...****.*.****...*..."
;这里的数据非常有趣,慢慢看吧 <br>
->".*.*..**********.*..*....*...*...**.****.*.*.." <br>
->".****.*....*.*******..*.***..*.....*.*..***.**" <br>
->".***.*...****....*X..*****************" <br>
| <br>
:004010CF 6865334000
push 00403365 <br>
<br>
* Possible StringData Ref from Data Obj ->"****************C*......*...****.*.****...*..."
<br>
->".*.*..**********.*..*....*...*...**.****.*.*.." <br>
->".****.*....*.*******..*.***..*.....*.*..***.**" <br>
->".***.*...****....*X..*****************" <br>
| <br>
:004010D4 68BC314000
push 004031BC <br>
<br>
* Reference To: KERNEL32.lstrcpyA, Ord:02DCh <br>
| <br>
:004010D9 E83A070000
Call 00401818
;简单的拷贝,不必理它。 <br>
:004010DE C70584314000CC314000 mov dword ptr [00403184],
004031CC ;注意一下这个变量,指向上面的图案中的第二行,为了
;方便后面的描述,记为
offsetOfPrettyPicture <br>
:004010E8 E830FFFFFF
call 0040101D
;处理第三次读取的18个数据 <br>
:004010ED C645FE00
mov [ebp-02], 00 <br>
:004010F1 33C0
xor eax, eax <br>
:004010F3 33C9
xor ecx, ecx <br>
<br>
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
<br>
|:00401128(C) <br>
| <br>
:004010F5 C645FF08
mov [ebp-01], 08
;大循环开始 <br>
<br>
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
<br>
|:0040111F(C) <br>
| <br>
:004010F9 806DFF02
sub byte ptr [ebp-01], 02 ;小循环开始
<br>
:004010FD 0FB64DFE
movzx ecx, byte ptr [ebp-02] <br>
:00401101 81C1E8344000 add
ecx, 004034E8 <br>
:00401107 8A01
mov al, byte ptr [ecx] <br>
:00401109 8A4DFF
mov cl, byte ptr [ebp-01] <br>
:0040110C D2E8
shr al, cl <br>
:0040110E 2403
and al, 03 <br>
:00401110 E81EFFFFFF
call 00401033
;注册在该call中实现!!!!!!!!!!!! <br>
:00401115 85C0
test eax, eax <br>
:00401117 7411
je 0040112A
;!!!!!!!!这里是关键所在,如果跳转则退出该函数,不
;产生任何变化 <br>
:00401119 0FB655FF
movzx edx, byte ptr [ebp-01] <br>
:0040111D 85D2
test edx, edx <br>
:0040111F 75D8
jne 004010F9
;小循环的循环次数为4次,[ebp-01]从8减为0 <br>
:00401121 FE45FE
inc [ebp-02] <br>
:00401124 807DFE12
cmp byte ptr [ebp-02], 12 <br>
:00401128 75CB
jne 004010F5
;大循环的循环次数为0x12(18),为数据缓冲区的大小 <br>
<br>
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
<br>
|:00401117(C) <br>
| <br>
:0040112A C9
leave <br>
:0040112B C3
ret <br>
<br>
看一看,call也不多,呵呵,真幸运! <br>
首先看看004010E8处的call 0040101D: <br>
<br>
:0040101D 8A15FB344000 mov
dl, byte ptr [004034FB] ;还记得吧上面提醒你注意的数据,就是第二次数据的和
<br>
:00401023 B912000000
mov ecx, 00000012 <br>
:00401028 B8E8344000
mov eax, 004034E8 <br>
:0040102D 3010
xor byte ptr [eax], dl <br>
:0040102F 40
inc eax <br>
:00401030 E2FB
loop 0040102D <br>
:00401032 C3
ret <br>
<br>
该函数的功能就是把第三次读取的18个数据与前面所得的和进行异或。看到这里,为了避免必要的麻烦,我修改了kwazyweb.bit文件,使得第一个字节为0x01,记住,要用16进制工具编辑,第二个字节为0x00,这样,所得的和为0,任何数和0异或时不变,利用这一点,省去了不少麻烦。后面接着随便输入18个字节。该文件大小一共是20个字节。
<br>
<br>
好,继续我们的分析。该函数里面有两个byte类型的局部变量,分别是[ebp-01]和[ebp-02] (还有一个word类型的变量[ebp-04],用于保存一个数据,下面会提到的)。有两个循环,大循环是为了处理18个数据,小循环对每一个数据进行4次处理,处理过程是右移6,4,2,0位之后,取出低2位,即若数据为0x12345678,则分别处理0x12,0x34,0x56,0x78。作为参数进入00401110
处的call 00401033。返回值决定是否退出当前函数。(多次试探知道注册在00401110 处的call 00401033里面实现)。让我们一起来看看这个关键的函数到底做了写什么?
<br>
<br>
:00401033 55
push ebp <br>
:00401034 8BEC
mov ebp, esp <br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -