发新话题
打印

[转载]DEF分析与打造其脱壳软件

[转载]DEF分析与打造其脱壳软件

  文章作者:nbw

   加壳软件一种可以对别的程序进行修改但是不影响其使用的工具软件。程序员经常利用加壳软件对自己的软件进行加壳,以加密或者压缩自己的软件。加壳后的软件一般来说难以被逆向分析,因此,脱壳软件应运而生。从某种角度来说,了解加壳和脱壳技术的原理是很有必要的。
   下面我以Def为例说明其加壳原理,同时,我们改造Def使其具有针对自身的脱壳功能。
Def是一款源码开放的小型加壳软件,精炼易懂,便于学习。其源代码和程序可以去http://protools.cjb.net下载。
   首先根据其源代码分析其加壳原理。它的加壳流程主要如下:
1、  以文件内存映象方式打开被加壳文件,并判断是否是有效的PE文件且不是Dll文件;
2、  遍历所有节表,根据节表名判断是否是输入表,资源节表或者其他节表,如果不是,定位到该节区,根据本节区大小对该节区的内容进行简单的异或加密,加密方式如下:
_encrypt:              ;加密该节区
      xor byte ptr[esi],al      ;进行异或加密
   inc esi         ;esi指向节区下一个字节
      dec eax         ;判断是否到节区尾部,同时也是下一次异或操作的变量
   jne _encrypt
      然后把节表名称修改为.def,对未进行加密的节表,添加未加密标志,具体见下文;
3、  为被加壳文件添加自解密部分,用于被加壳文件运行时候自行解密。这一段可以参考源代码中的_loader部分。这段自解密代码被添加到文件节表的后面,同时修改文件的入口地址为此处的偏移地址。添加自解密部分的代码如下:
      mov esi,offset _loader    ; 初始化_loader的偏移地址
   mov ecx,_loader_size      ; 初始化loader部分的大小
      rep movsb          ; 把loader部分拷贝到被加壳文件的节表尾部
                   ;其实这里最好判断一下是否有足够空间放置本段代码
4、  最后关闭文件内存映象;
根据上面的流程分析,再仔细研究一下其代码,相信你可以很快明白它的具体工作方式。下面我们来修改def,使其具有脱壳功能。
   Def手工脱壳很简单,我以脱去Def自身的壳为例,说明其脱壳流程:
1、  用Trw载入Def;
2、  F10单步运行至xxxx:400244  push  dword  ptr  00401000  处,其中00401000为Def原来的入口地址。下命令Suspend,将进程挂起,F5回到windows界面;
3、  打开Peditor,点task,选择被挂起的Def进程,点右键dump(full),保存为unDef;
4、  用Peditor修改unDef文件的入口地址为00001000,注意这里是00401000减去00400000得到的。
好了,这样unDef就是Def的脱壳文件。我们现在要修改Def为自身的脱壳程序,也就是要对unDef进行处理。
首先,脱壳程序应该可以判断一个文件是否被Def加壳,利用Def的判断方式,判断第一个节表名称是否为.def便可以。故此,修改:
:00401091 813A2E646566        cmp dword ptr [edx], 6665642E    ;.def ?
:00401097 0F858B000000        je 00401128
为:
:00401091 813A2E646566        cmp dword ptr [edx], 6665642E
:00401097 0F848B000000        jne 00401128  ;如果第一个节表名不为.def则跳出
                                ;请注意这里最好不要改成jmp
现在就可以对加壳文件进行脱壳了,由于def采用了简单的异或加密,因此解密部分不需要修改。找个加壳文件实验一下,竟然发生异常。为什么这样呢?因为Def并不是把所有的节表都加密,对于引入表,资源节表等,def是不处理的。但我们的unDef会把所有的节表都进行解密,因此当然会发生错误。也许你会问,在程序中不是有call _is_encryptable(也就是:004010A7  call 004011A0)用来判断是否应该被加密么?不错,虽然如此,但是仔细再看一下_is_encryptable这个函数,它通过节表名来判断节表的修改合法性,而被加壳的文件所有节表名称都被改成了.def。因此,对这个函数来说加壳文件中所有的节表都应该被修改。
难道我们就没有办法判断了么?当然不是,仔细研究一下加壳文件的引导部分,也就是Def源代码中的_loader部分,在程序自身解密的时候有cmp byte ptr [esi+07], 00,其中esi指向节表头,如果[edx+07]=0 则跳过解密部分,否则进行解密。这样一来,我们修改unDef的解密部分。从VA=004010A7开始,修改后如下:
:004010A7 807A0700           cmp byte ptr [edx+07], 00 ;判断节区修改标志
:004010AB 90               nop  ;保证文件后面的内容不变
:004010AC 90               nop
:004010AD 90               nop
:004010AE 740F              je 004010BF  ;如果不该解密,便跳过解密部分
到这里,就可以把所有加密部分恢复。但是脱壳文件仍然无法运行,因为我们还没有把文件的入口地址修改过来。看一下def如何修改入口地址,你可以很容易编写恢复入口地址的代码,如下:
:004010D6 50               push eax
:004010D7 8B4225            mov eax, dword ptr [edx+25]  ;edx指向节表最后
                                   ;[edx+25]为真正的入口地址
:004010DA 2D00004000          sub eax, 00400000    ;入口地址的RVA->eax
;减去imagebase,我这里图省事,直接减去00400000H,正规的应该从文件中读取
:004010DF 894728            mov dword ptr [edi+28], eax  ;edi+28指向入口地址
:004010E2 58               pop eax
:004010E3 E92B000000          jmp 00401113    ;跳转到添加_loader处
:004010E8 90               nop          ;保证原来的文件内容不变
最后,修改_loader处的代码为自己的信息(这就是上面为何跳到401113)。把 "The Undef Made by NBW  QQ:37122085  http://nboy.cnwlt.com"的ASCII码覆盖到文件地址1154处,同时要修改:
:00401118 B92A000000          mov ecx, 0000002A
因为这个地方定义了添加的新代码的长度,如下:
:00401118 B93A000000          mov ecx, 00000036 ;36H就是我添加的信息的长度
   到此,我们的unDef就制作完毕了,找一个被Def加壳的程序,用unDef进行脱壳,OK!很好用。
   最后再多说几句,上面的这些地址除注明外都是程序的虚拟地址,在修改unDef的时候,不妨用Hiew打开,按F3,再按F2进入Asm修改状态,你可以直接输入汇编程序进行修改,但是由于Hiew支持的Asm代码不全面,因此有些语句还需要在16进制状态进行修改。从这个修改过程也可以看到,由于加壳软件对原文件的破坏,我们做的脱壳软件并不可能100%地恢复加壳软件原状,至少节表的名称和属性没有修改过来。因此,一些软件被专家级别的加壳软件所加壳,在脱壳的时候出现较大偏差是很正常的。



以下为代码分析:

;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪
; DEF - prostacki encryptor plikow PE EXE
; kompatybilny z 95,NT
;
;原作: bart/xtreeme
;
;这是一款典型的加壳软件,软件可以进行简单的异或加密,并且也未对输入表等进行处理,总体来说非常简单。
;其源代码是开放的,并且非常简练和易读,仔细看一看会有不少收获。源代码也有注释,但是我现在还不明白那是哪国天书,
;要有高手明白,不妨告知一二,这里先谢过了。
;
;
;
;注释:nbw
;我的资料被人拿走了,因此有些地方应该还有问题,不足指出还请大家包涵和指出
;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪

.586                ; 定义用的指令结合
.mmx                ; +mmx
.model flat,stdcall

includelib  e:\dev\masm\lib\kernel32.lib   ; 包含所需类库
includelib  e:\dev\masm\lib\user32.lib
includelib  e:\dev\masm\lib\comdlg32.lib

include    e:\dev\masm\include\kernel32.inc
include    e:\dev\masm\include\user32.inc
include    e:\dev\masm\include\comdlg32.inc

include    e:\dev\masm\include\windows.inc
include    pe.inc          ;pe.inc中定义了所需的常量,多与PE格式有关

.data?
   lpFilename  db 256 dup(?)     ; 文件名
   lpFile    MEMF <>      ; 文件句柄
   lpPeheader  dd ?        ; PE头
   lpSectionTable  dd ?        ;指向第一个节表的头部

.data
   lpOfn     dd lOfn      ; 定义打开文件所需要的结构
        dd 0        ; hWnd
        dd 0        ; hInst
        dd offset szFilter  ; filtr
        dd 0        
        dd 0        
        dd 0        
        dd offset lpFilename   
        dd 256      
        dd 0        ; lpstrFileTitle;
        dd 0        ; nMaxFileTitle;
        dd 0        ; lpstrInitialDir;
        dd offset szCaption ; lpstrTitle;
        dd OFN_HIDEREADONLY ; Flags;

        dw 0        ; nFileOffset;
        dw 0        ; nFileExtension;
        dd 0        ; lpstrDefExt;
        dd 0        ; lCustData;
        dd 0        ; lpfnHook;
        dd 0        ; lpTemplateName;
   lOfn      equ $-lpOfn


   szCaption  db &#39;DEF v1.0 by bart/xt - wybierz plik do zaszyfrowania&#39;,0
   szFilter   db &#39;Pliki EXE (*.exe)&#39;,0,&#39;*.exe&#39;,0
        db &#39;Wszystkie pliki (*.*)&#39;,0,&#39;*.*&#39;,0,0

   szError    db &#39;Nieprawidlowy format pliku!&#39;,0
   szDef     db &#39;DEF v1.0 by bart/xt&#39;,0

.code
_start:


   push   offset lpOfn        ; lpOfn偏移入栈(废话)
   call   GetOpenFileNameA      ; 调用通用对话框打开文件
   test   eax,eax         ; 判断出错否?
   je  _exit

   push   offset lpFilename     ; 文件路径入栈
   call   _open_file      
   inc eax         ; 这种判断方式也算一种技巧
   je  _exit         

   test   ecx,ecx
   je  _exit         

   dec eax         

   mov ebx,offset lpFile     ;ebx->文件句柄,也相当于文件头
   assume  ebx:ptr MEMF        ;把ebx赋值为MEMF结构

   mov [ebx].file_handle,eax     ;保存句柄
   mov [ebx].file_size,ecx    ;保存大小

   push   eax         
   push   ecx         
   call   _map_file        ;以文件内存映像的方式打开文件,这样个方式的好处真是多多
   test   eax,eax         
   je  _exit_close      

   test   ecx,ecx
   je  _exit_close      

   mov [ebx].mem_ptr,eax     
   mov [ebx].mem_handle,ecx      
;下面是文件合法性判断
   cmp word ptr[eax],&#39;ZM&#39;    ;判断文件头部的Dos标志“MZ”
   jne _bad_format

   add eax,dword ptr[eax+3Ch]    ; eax->文件NTHeader
   mov lpPeheader,eax      
   xchg   eax,edi         ;edi->文件NTHeader

   cmp dword ptr[edi],00004550h   ; 判断是否是PE文件
   jne _bad_format      
               

   cmp dword ptr[edi+entrypointRVA],0  ;判断文件的入口地址为0否?
   je  _bad_format      

   test   word ptr[edi+DllFlags],2000h   ; 判断是否是Dll文件
   jne _bad_format                    

   movzx  edx,word ptr[edi+NtHeaderSize]  ;edx->NtHeader尾部,我记不清楚这里是否是节表开头了,你可以查一下
   lea edx,[edi+edx+18h]     ; edx->节表头部

   cmp dword ptr[edx],&#39;fed.&#39;     ; 判断该文件是否被Def加壳
   je  _bad_format      


   mov lpSectionTable,edx    ; 保存节表头部

   movzx  ecx,word ptr[edi+numObj]   ; ecx->节表数目

; edx <-- 节表头部
; edi <-- PE头
; ecx <-- 节表数目

_encrypt_sections:
                ; 判断edx指向的节区是否该加密
   call   _is_encryptable      
   test   eax,eax         
   je  _encrypt_skip        

   mov esi,dword ptr[edx+objpoff]  ;esi->节区文件偏移地址
   add esi,[ebx].mem_ptr     
                ;esi->节区虚拟地址

   mov eax,dword ptr[edx+objpsize] ;eax->节区大小

_encrypt:             ;加密该节区
   xor byte ptr[esi],al      ;进行异或加密
   inc esi         ;指向节区下一个字节
   dec eax         ;判断是否到节区尾部,同时也是下一次异或操作的一个变量
   jne _encrypt

   inc eax         
_encrypt_skip:            
   mov dword ptr[edx],&#39;fed.&#39;     ;修改节表名称
   bswap  eax         ;eax由01000000改为00000001,如果开始为0,则仍然为0
   mov dword ptr[edx+4],eax      ;把eax写入节表名称后面,这样做是为了标志该节表是否被加密
                ;1->被加密
                ;0->未被加密
   mov dword ptr[edx+objflags],0C00000E0h  ;修改节区属性为可写可读

   add edx,objlen       ;edx->下一个节表
   loop   _encrypt_sections     ;转入下一个节表的处理  


; korygowanie offsetow loadera
   mov edx,dword ptr[edi+imagebase]   ;读入基址
   mov dword ptr[_ldr_imagebase],edx  ;保存基址,便于被加壳文件的载入

   mov eax,dword ptr[edi+entrypointRVA];读入入口地址
   add eax,edx         ;入口地址的VA
   mov dword ptr[_ldr_host],eax   ;保存入口地址,便于被加壳文件的载入

   mov eax,lpSectionTable   
   sub eax,[ebx].mem_ptr
   add eax,edx         ; VA
   mov dword ptr[_ldr_sections],eax   ;保存节表头的地址

   movzx  ecx,word ptr[edi+numObj]   ;节表数目
   mov byte ptr[_ldr_count],cl

   imul   ecx,objlen       ;ecx->节表大小

   mov eax,lpSectionTable    ;
   sub eax,[ebx].mem_ptr

   add eax,ecx         ;eax->节表尾部的RVA

   mov dword ptr[edi+entrypointRVA],eax;再次保存入口地址,上面的保存其实多余

   add eax,[ebx].mem_ptr
   xchg   eax,edi         
   mov esi,offset _loader    ; 初始化_loader的偏移地址
   mov ecx,_loader_size      ; 初始化loader部分的大小
   rep movsb          ; 把loader部分拷贝到被加壳文件的节表尾部
                ;其实这里最好判断一下是否有足够空间放置本段代码

   push   -1         
   call   MessageBeep      ;响铃
   jmp _exit_unmap

_bad_format:              
   push   10h         
   push   offset szDef
   push   offset szError
   push   0
   call   MessageBoxA

_exit_unmap:              
   push   [ebx].mem_ptr
   push   [ebx].mem_handle
   call   _unmap

_exit_close:
   push   [ebx].file_handle     
   call   CloseHandle

_exit:
   push   -1
   call   ExitProcess      ; bye bye
; 下面这一段被放入被加壳文件的节表尾部,作为程序运行时候的解密部分

_loader:
   mov esi,987654321        ;这里的987654321只是为了给_ldr_sections留够4个字节的空间
_ldr_sections  equ dword ptr $-4     ;定义_ldr_sections及其地址,请注意查找前面的设置

   push   0          ;节表数目
_ldr_count  equ byte ptr $-1
   pop ecx         ;ecx->节表数目,在前面有设置

_ldr_next:            ;解密开始
   cmp byte ptr[esi+7],0     ;判断这个节区是否该解密,根据[esi+7]判断,请参考前面的注释
   je  _ldr_not_encrypted    ;如果不该解密,越过下面的部分

   mov eax,dword ptr[esi+objrva]  ;eax->节区的Rva
   add eax,987654321        ;eax->节区的VA
_ldr_imagebase  equ dword ptr $-4     ;请注意参考前面的设置

   mov edx,dword ptr[esi+objpsize] ;节区大小

_ldr_decrypt:             ;异或解密
   xor byte ptr[eax],dl
   inc eax         ;下一个字节
   dec edx
   jne _ldr_decrypt

_ldr_not_encrypted:

   add esi,objlen       ;esi->下一个节区
   loop   _ldr_next        ;开始下一个节区的解密

   push   987654321        ;程序原来的入口地址入栈,这样,下面的ret便返回到_ldr_host处执行
_ldr_host  equ dword ptr $-4
   ret

_loader_end:
_loader_size equ $-_loader

;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪
;
;  mov edx,offset section_header
;  call   _is_rsrc
;
;  sprawdza, czy sekcja zawiera zasoby
;
;  na wyjsciu:
;  eax - 1 sekcja zasobow
;      0 brak zasobow
;
;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪

_is_rsrc proc near    ;判断节表名称是否为rsr或者reso,因为这些节区不可以加密

   cmp dword ptr[edx],&#39;rsr.&#39;     ; rsrc
   je  _rsrc_section

   cmp dword ptr[edx],&#39;oser&#39;     ; resource
   je  _rsrc_section

   mov eax,dword ptr[edx+objrva]
   cmp eax,dword ptr[ebx+resource]
   je  _rsrc_section        

   sub eax,eax
   ret

_rsrc_section:
   sub eax,eax
   inc eax
   ret

_is_rsrc endp



;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪
;
;  mov edx,offset section_header
;  call   _is_encryptable
;
;  eax - 0 不可加密
;      1 可加密
;
;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪

_is_encryptable proc near
   push   ebx
   mov ebx,dword ptr[lpPeheader]

   call   _is_rsrc        
   dec eax
   je  _bad_section


   cmp dword ptr[edx],&#39;ler.&#39;     ; reloc
   je  _bad_section

   cmp dword ptr[edx],&#39;ade.&#39;     ; edata
   je  _bad_section

   cmp dword ptr[edx],&#39;ete.&#39;     ; etext
   je  _bad_section

   cmp dword ptr[edx],&#39;adr.&#39;     ; rdata
   je  _bad_section

   cmp dword ptr[edx],&#39;slt.&#39;     ; tls
   je  _bad_section

   cmp dword ptr[edx],&#39;adi.&#39;     ; idata
   je  _bad_section


   sub eax,eax

   cmp dword ptr[edx+objpoff],eax  ;判断节区的属性是否合法,下面的几个也是
   je  _bad_section        

   cmp dword ptr[edx+objpsize],eax
   je  _bad_section        


   mov eax,dword ptr[edx+objrva]  ;保存rva

   cmp eax,dword ptr[ebx+resource] ;判断节区的rva是否和资源的rva一样,如果一样则不可加密
   je  _bad_section      

   cmp eax,dword ptr[ebx+edatadir] ;我也不太清楚,你可以跟踪看一下
   je  _bad_section        

   cmp eax,dword ptr[ebx+import]
   je  _bad_section

   cmp eax,dword ptr[ebx+reloc]   ;reloc是说重定位表
   je  _bad_section        

   cmp eax,dword ptr[ebx+tls]    ;我也不知道
   je  _bad_section        ;
               
   sub eax,eax
   jmp _check_exit

_bad_section:
   or  eax,-1

_check_exit:
   inc eax
   pop ebx

   ret

_is_encryptable endp


;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪
;下面是文件的打开和关闭部分,我就不献丑写注释了。大家要不太清楚,查以下书好了
;  push   offset lpFilename
;  call   _open_file
;
;  Otwiera plik do zapisu i odczytu z podanej lokalizacji
;
;  na wejsciu:
;  lpFilename  - nazwa pliku do otworzenia
;
;  na wyjsciu:
;  eax - uchwyt pliku lub -1 jesli blad
;  ecx - rozmiar pliku
;
;  modyfikowane rejestry:
;  eax,ecx,edx
;
;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪

_open_file proc near
   pop eax
   pop edx
   push   eax

   push   edx

   push   FILE_ATTRIBUTE_ARCHIVE    ; atrybuty
   push   edx         ; nazwa pliku
   call   SetFileAttributesA    ; usun atrybuty blokujace dostep do zapisu
   
   pop edx         ; pop nazwa pliku

   sub eax,eax
   push   eax
   push   FILE_ATTRIBUTE_NORMAL
   push   OPEN_EXISTING        ; akcja, otworz plik
   push   eax
   push   eax
   push   GENERIC_READ + GENERIC_WRITE   ; tryb dostepu
   push   edx         ; nazwa pliku
   call   CreateFileA
   
   cmp eax,-1          ; sprawdz wartosc zwrocona przez CreateFileA
   je  _open_err        ; jesli to -1 to znaczy, ze wystapil blad
                ; wyjdz z takim wynikiem z funkcji

   push   eax         ; zapamietaj na stosie uchwyt pliku

   push   0          ; 0 dla plikow mniejszych niz 4gb
   push   eax         ; uchwyt pliku
   call   GetFileSize      ; pobierz rozmiar pliku

   pop ecx         ; pop, uchwyt pliku do ecx
   xchg   eax,ecx         ; zamien wartosci w rejestrach, tak, ze
                ; w eax znajdzie sie uchyt pliku a w ecx
                ; rozmiar pliku
_open_err:
   ret            ; wyjscie z funkcji

_open_file endp


;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪
;
;  push   hFile
;  push   cbSize
;  call   _map_file
;
;  Mapuje plik do pamieci, wszystkie operacje dokonywane na pamieci maja fizyczne
;  odzwierciedlenie na dysku
;
;  na wejsciu:
;  hFile  - uchwyt pliku otwartego w trybie do odczytu i zapisu
;  cbSize  - rozmiar pliku
;
;  na wyjsciu:
;  eax - wskaznik do mapowanego pliku lub 0 jesli blad
;  ecx - uchwyt mapowanego pliku
;
;  modyfikowane rejestry:
;  eax,ecx,edx
;
;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪

_map_file proc near

   pop eax         ; adres powrotu
   pop ecx         ; rozmiar pliku
   pop edx         ; uchwyt pliku

   push   eax

   sub eax,eax
   push   eax
   push   ecx         ; rozmiar pliku(+opcjonalnie rozmiar
                ; dodtkowego obszaru pamieci)

   push   eax         ;
   push   PAGE_READWRITE       ; tryb dostepu do mapy pliku
   push   eax
   push   edx         ; uchwyt pliku
   call   CreateFileMappingA

   push   eax         ; zapamietaj uchwyt mapy pliku

   sub edx,edx         ; zeruj edx

   push   edx         ; ilosc bajtow do mapowania, gdy 0
                ; mapowany jest caly plik
   push   edx         ;
   push   edx         ;
   push   FILE_MAP_WRITE       ; flagi dostepu
   push   eax         ;
   call   MapViewOfFile        ; w eax wskaznik do mapy pliku

   pop ecx         ; uchwyt mapy pliku do ecx
   ret
_map_file endp


;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪
;
;  push   lpMap
;  push   hMap
;  call   _unmap
;
;  zamyka mapowany plik + zapisuje zmiany jakie dokonano na mapie pliku
;
;  na wejsciu:
;  lpMap     - wskaznik do mapy pliku
;  hMap      - uchwyt mapy pliku
;
;  na wyjsciu:
;  brak
;
;  modyfikowane rejestry:
;  eax,ecx,edx
;
;哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪

_unmap  proc near
   pop eax

   pop ecx         ; hMap
   pop edx         ; lpMap

   push   eax

   push   ecx         ; zapamietaj parametr dla CloseHandle

   push   edx         ; lpMap
   call   UnmapViewOfFile      ; usuwa obraz mapy pliku z przestrzeni adresowej
                ; naszego procesu

   call   CloseHandle      ; zamknij mape pliku

   ret
_unmap  endp

end _start
曾几何时,有人对我说:装B遭雷劈。我说:去你妈的。于是,这个人又对我说:如果再说脏话,上帝会惩罚你的。我说:我操上帝。结论:彪悍的人生不需要上帝。

TOP

发新话题