• 标 题:灌水:Dll DIY的另一种修改方式 (10千字)
  • 作 者:ArchFire/ATA
  • 时 间:2003-4-14 14:32:13
  • 链 接:http://bbs.pediy.com

Dll DIY: 另一种修改方式
作者:ArchFire/ATA


PEdiy已经被大牛门玩的烂熟,这里来点dll的修改,仅供一笑:)

问题来源于这里:hX*p://www.cpnn.com.cn/,网页文件被加密为btk文件,如果你查看源文件只会看到被加密后的文本。它是怎么作的?

首先浏览网页时,会下载ie的一个插件,文件名是:bk_paper.dll,加密后的文本由这个dll来负责解密,以此保证不能很容易的拷贝出来。

经过简单的分析和跟踪,发现解密出的内容是以明文存在于内存中,这样就有机会将它保存出来。为保存文件至少需要下面几个api: createfile, setfilepointer, writefile, closehandle。观察原文件,并无这几个。如果让我来手工将它们导入到IT表中,肯定是要晕倒~~ 找找其它机会,发现引入表中有:loadlibrary, getprocaddress, freelibrary,呵呵,有机可乘。

记得hying说过,dll 的 entry 会在加载和卸载时各运行一次,那就可以在它加载时再load一个自己写的dll,取得保存函数的地址,并保存起来;在退出时将自己的dll也卸载掉,这样会是很安全;在内存中出现明文的时刻调用我们的保存函数就可以存盘。这样作的好处是对原文件修改的不多,自己定制的dll有很强的灵活性。

下面看看具体作法:

1。编译一个用于对原文件打补丁的代码:

;crack source.asm
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib

;.data
;hDll    dd 0
;    dd 0

.code
.RADIX 16
start:                    ;copy the code to imagebase + 3030
        nop
    nop
    call delta
delta:
    pop esi                ;
    add esi, 0a9            ;imagebase + 30e0
    push esi
    pop edi                ;edi=esi=temp var, offset of 2 dwords
    ;mov esi, 100030e0
    lodsd                ;eax=dll handle
    test eax, eax            ;if "save.dll" is loaded
    jnz UnLoadDll
    call LoadDll            ;if not, load it.
    db "save.dll", 0
LoadDll:
    call LoadDlla
    jmp LoadDllb
LoadDlla:
    db 0ff, 25, 0a4, 45, 01, 10    ;use api-LoadLibrary
    ;call LoadLibrary
LoadDllb:
    nop
    nop
    nop
    test eax, eax
    jz Next1            ;if error occurs, then returns
    stosd                ;else save dll handle
    call FindFunc
    db "SaveIt", 0            ;
FindFunc:
    push eax
    db 0ff, 15, 9c, 45, 01, 10    ;call GetProcAddress
    nop
    nop
    nop
    nop
    test eax, eax
    jz Next1
    stosd                ;if no error, save it.
    jmp Next1

UnLoadDll:
    push eax
    db 0ff, 15, 0c0, 45, 01, 10    ;call FreeLibrary
Next1:
        nop
    push 01
    pop eax
    ret 0ch
        
        ;invoke ExitProcess,NULL
end start

2。上面的编译完成后用winhex将二进制代码复制到要打补丁的位置,我选的是:imagebase+3030。

来看一下修改前后的关键文件,还要记得把.text的节属性改为可写~:


dll entry的原始状态:

:10001ECF 6828390110              push 10013928
:10001ED4 E85EF6FFFF              call 10001537

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:10001EC6(U), :10001ECD(C)
|
:10001ED9 6A01                    push 00000001
:10001EDB 58                      pop eax            ;eax=1
:10001EDC C20C00                  ret 000C            ;返回


:10001EDF CC                      int 03
:10001EE0 CC                      int 03
:10001EE1 CC                      int 03
:10001EE2 CC                      int 03

修改后的:

:10001ED4 E85EF6FFFF              call 10001537

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:10001EC6(U), :10001ECD(C)
|
:10001ED9 E952110000              jmp 10003030
:10001EDE CC                      int 03

...

|
:10003028 B809000280              mov eax, 80020009
:1000302D EBD3                    jmp 10003002
:1000302F CC                      int 03

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10001ED9(U)
|
:10003030 90                      nop
:10003031 90                      nop
:10003032 E800000000              call 10003037

* Referenced by a CALL at Address:
|:10003032 
|
:10003037 5E                      pop esi
:10003038 81C6A9000000            add esi, 000000A9
:1000303E 56                      push esi
:1000303F 5F                      pop edi
:10003040 AD                      lodsd
:10003041 85C0                    test eax, eax
:10003043 7541                    jne 10003086
:10003045 E809000000              call 10003053
:1000304A 7361                    jnb 100030AD
:1000304C 7665                    jbe 100030B3
:1000304E 2E                      BYTE 02eh


:1000304F 64                      BYTE 064h


:10003050 6C                      insb
:10003051 6C                      insb
:10003052 00                      BYTE 00h


* Referenced by a CALL at Address:
|:10003045 
|

* Reference To: KERNEL32.LoadLibraryA, Ord:0000h
                                  |
:10003053 E802000000              Call 1000305A
:10003058 EB06                    jmp 10003060

* Reference To: KERNEL32.LoadLibraryA, Ord:0000h
                                  |
:1000305A FF25A4450110            Jmp dword ptr [100145A4]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10003058(U)
|
:10003060 90                      nop
:10003061 90                      nop
:10003062 90                      nop
:10003063 85C0                    test eax, eax
:10003065 7426                    je 1000308D
:10003067 AB                      stosd
:10003068 E807000000              call 10003074
:1000306D 53                      push ebx
:1000306E 61                      popad
:1000306F 7665                    jbe 100030D6
:10003071 49                      dec ecx
:10003072 7400                    je 10003074

* Referenced by a CALL at Address:
|:10003068 
|

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10003072(C)
|
:10003074 50                      push eax

* Reference To: KERNEL32.GetProcAddress, Ord:0000h
                                  |
:10003075 FF159C450110            Call dword ptr [1001459C]
:1000307B 90                      nop
:1000307C 90                      nop
:1000307D 90                      nop
:1000307E 90                      nop
:1000307F 85C0                    test eax, eax
:10003081 740A                    je 1000308D
:10003083 AB                      stosd
:10003084 EB07                    jmp 1000308D

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:10003043(C)
|
:10003086 50                      push eax

* Reference To: KERNEL32.FreeLibrary, Ord:0000h
                                  |
:10003087 FF15C0450110            Call dword ptr [100145C0]

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:10003065(C), :10003081(C), :10003084(U)
|
:1000308D 90                      nop
:1000308E 6A01                    push 00000001
:10003090 58                      pop eax
:10003091 C20C00                  ret 000C


:10003094 CC                      int 03
:10003095 CC                      int 03
:10003096 CC                      int 03
:10003097 CC                      int 03
:10003098 CC                      int 03


3。修改原文件,在内存中有明码处调用我们的函数来保存:


:1000B263 8BFC                    mov edi, esp
:1000B265 F3                      repz
:1000B266 A5                      movsd
:1000B267 8D8D6CE2FFFF            lea ecx, dword ptr [ebp+FFFFE26C]
:1000B26D E80960FFFF              call 1000127B
:1000B272 8DB535EFFFFF            lea esi, dword ptr [ebp+FFFFEF35]
:1000B278 8D7DF4                  lea edi, dword ptr [ebp-0C]
:1000B27B A5                      movsd
:1000B27C 33C0                    xor eax, eax
:1000B27E 3945F0                  cmp dword ptr [ebp-10], eax
:1000B281 A5                      movsd
:1000B282 7616                    jbe 1000B29A
:1000B284 8B4DE8                  mov ecx, dword ptr [ebp-18]
:1000B287 8B55EC                  mov edx, dword ptr [ebp-14]
:1000B28A 8D0CCA                  lea ecx, dword ptr [edx+8*ecx]

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1000B298(C)
|
:1000B28D 8A5405F4                mov dl, byte ptr [ebp+eax-0C]
:1000B291 301401                  xor byte ptr [ecx+eax], dl
:1000B294 40                      inc eax
:1000B295 3B45F0                  cmp eax, dword ptr [ebp-10]
:1000B298 72F3                    jb 1000B28D

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:1000B282(C)
|
:1000B29A 8D8D40EFFFFF            lea ecx, dword ptr [ebp+FFFFEF40]
:1000B2A0 E87462FFFF              call 10001519
:1000B2A5 8D8D6CE2FFFF            lea ecx, dword ptr [ebp+FFFFE26C]
:1000B2AB E8915DFFFF              call 10001041
:1000B2B0 8B45EC                  mov eax, dword ptr [ebp-14]        ;eax指向明文,所以要改一下
:1000B2B3 5F                      pop edi
:1000B2B4 5E                      pop esi
:1000B2B5 5B                      pop ebx
:1000B2B6 C9                      leave
:1000B2B7 C20400                  ret 0004


:1000B2BA CC                      int 03
:1000B2BB CC                      int 03
:1000B2BC CC                      int 03
:1000B2BD CC                      int 03
:1000B2BE CC                      int 03
:1000B2BF CC                      int 03
:1000B2C0 CC                      int 03
:1000B2C1 CC                      int 03
:1000B2C2 CC                      int 03




修改后的:
:1000B2B4 5E                      pop esi
:1000B2B5 5B                      pop ebx
:1000B2B6 C9                      leave
:1000B2B7 FF15E4300010            call dword ptr [100030E4]    ;懒了点,应该先检查一下是否为空
:1000B2BD C20400                  ret 0004



4。自定saveit函数,eax为明文首址,存文件即可,记得寄存器和状态的保护和恢复。

.586
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
;.RADIX 16
;MsgTitle    db    "sss", 0
;MsgContend    db    "aaa", 0
dByteDone        dd    0


.code
.RADIX 16
align    2
DllEntry proc hInstDLL:HINSTANCE, reason:DWORD, reserved1:DWORD
    xor eax, eax
    inc eax
        ret
DllEntry Endp
;
SaveIt    proc
    pusha
    pushf
    ;save eax
    push eax
    pop ebx
    invoke lstrlen, eax
    mov esi, eax
    test eax, eax
    jz CreateErr
    ;createfile
    xor eax, eax
    push eax
    push eax
    push OPEN_ALWAYS
    push eax
    push eax
    push GENERIC_WRITE
    call CreateIt
    db "c:\iloveyou.txt", 0
CreateIt:
    call CreateFileA        ;createfile
    mov edi, eax
    inc eax
    jz CreateErr
    dec eax
    push FILE_BEGIN
    xor eax, eax
    push eax
    push eax
    push edi
    call SetFilePointer        ;set pointer
    ;
    mov dByteDone,0
    push 0
    push offset dByteDone
    push esi
    push ebx
    push edi
    call WriteFile            ;write to file
    ;

    invoke CloseHandle, edi        ;close
CreateErr:
    popf
    popa
    ret
SaveIt    endp



End DllEntry

因为我很懒,都给它存到一个文件中,后来的内容会覆盖先前的~~手可要快一点。