Trao đổi với tôi

http://www.buidao.com

3/14/10

[TASM] Writing a DLL in tasm32

Author: Benina
My blog: rootbiez.tk
Download : [source]
Bài viết tóm tắt cách tạo 1 dll trong tasm32. Ở đây ko nói về lý thuyết dll. Bài này chỉ là một bài thực hành. Tôi viết chỉ để lưu trữ cho riêng tôi.
Một dll cơ bản như sau:

   1:                          .586p
   2:                          .model  flat, stdcall
   3:                          locals
   4:                          jumps
   5:                          
   6:  include                 c:\tasm32\include\shitheap.inc
   7:  include                 dll.inc
   8:  include                 struct.inc
   9:   
  10:                          .data
  11:  String1              db      "kernel32.dll", 0
  12:  hmodule              dd      ?
  13:   
  14:                          .code
  15:  ;dllmain, entrypoint dll
  16:  start                   proc
  17:                          arg     imagebase
  18:                          arg     reason
  19:                          arg     reserved
  20:                          
  21:                          pushad                       
  22:                          cmp     reason, 1
  23:                          jne     __e_dllinit
  24:   
  25:               ;(code here)
  26:   
  27:  __e_dllinit:            popad
  28:                          mov     eax, 1
  29:                          leave
  30:                          retn    0ch
  31:                          endp
  32:                          
  33:  public my_Function
  34:  my_Function:
  35:                          ;code my func to export
  36:                          Retn
  37:   
  38:  end     start
  39:   
.Phân tích:

0/Header file:

   1:                          .586p
   2:                          .model  flat, stdcall
   3:                          locals
   4:                          jumps

.586p :Dùng các chỉ thị của bộ vi xử lý 586p trở lên
.model flat, stdcall : Bộ nhớ dùng flat memory model. Và quy ước gọi hàm là stdcall
jumps : Làm cho TASM tìm ra vị trí của một lệnh nhảy có điều kiện.
locals : Cho phép block-scoped symbols

1/Giá trị trả về của dllmain retn 0ch:

Phần khởi trị đầu tại entry point của chương trình của bạn phải quite với một chỉ lệnh ret 0Ch và ko exit với ExitProcess như file exe. Lý do đơn giản là loader gọi entry point gống như sau:

   1:  BOOL WINAPI DllEntryPoint(
   2:                  HINSTANCE  hinstDLL,        // handle of DLL module
   3:                  DWORD  fdwReason,           // reason for calling function
   4:                  LPVOID  lpvReserved         // reserved
   5:                 );
Nói một chút về lệnh RETN: Lệnh “RETN 4” có nghĩa là chuyển điều khiển EIP đến [esp+4] tức là sẽ bỏ qua 4 bytes addr trên stack để lấy addr cho EIP tại esp+4.
Chúng ta chú ý:
Ta có 4 tham số cho hàm proc của dll:

                        arg     imagebase
                        arg     reason
                        arg     reserved
Vì vậy theo như lệnh retn nói trên chúng ta sẽ trả về : retn 0ch
2/Tham số reason:
Có các giá trị sau:

Setting                 Value   Description
DLL_PROCESS_ATTACH      1       New process has started
DLL_THREAD_ATTACH       2       New thread has been created
DLL_THREAD_DETACH       3       Thread is about to be terminated
DLL_PROCESS_DETACH      0       Process is about to terminate

DLL đụoc gọi khi nó bị gắn vào process hay thread hay khi nó tách ra từ một process hay thread. Do đó tham số reason sẽ có các giá trị trên

3/Exported func được viết như sau:

 public myFunction
 
 myFunction PROC
     ; your code goes here ...
     ret
 myFunction ENDP

Hay

public my_Function
my_Function:
                        ;code my func to export
                        Retn

Nếu bạn ko hai báo func của bạn là publuc thì linker sẽ cho bạn cảnh báo.

4/Bảo quản thanh ghi:

Vài thanh ghi phải được bảo quản trong DLL entrypoint của chúng ta. Điều này rất quan trọng, nếu bạn ko bảo quản (preserve) chúng thì process loaded DLL sẽ kết thúc mà ko đưa ra thông báo lỗi gì sau khi DLL entrypoint đã run. Tôi ko biết những thanh ghi gì được bảo quản, nhưng ESI là chắc chắn. Một cách tốt nhất là dùng PUSHAD và POPAD để bảo quản tất cả các thanh ghi. Giá trị trả về chỉ quan trọng khi entrypoint được gọi với giá trị DLL_PROCESS_ATTACH cho tham số reason. Nó phải khác zero vì mục đích là đề xuất với hàm LoadLibrary API rằng khởi trị đầu thành công. Nó trả về zero thì DLL sẽ remove khỏi process. Vì vậy sau cùng của dll ta cần set eax:

                        mov     eax, 1
                        leave

5/Viết file .def:

Để export hàm của bạn, bạn cần write một file '.def'
Các file definition files (.def) này dường như rất giống C++. Tôi ko biết nhiều về chúng nhưng tôi biết bạn có thể viết như sau cho việc export hàm của bạn:
EXPORTS
myFunction

File .def nên đặt cùng tên với file asm của dll

6/Các file inc được kèm vào như dll.inc:

Dùng để chứa các hàm import, ví dụ

extrn ActivateActCtx:proc
extrn AddAtomA:proc
extrn AddAtomW:proc

còn struct.inc, để chứa các cấu trúc phục vụ cho coding dll

7/Biên dịch:

Không có resource, ta tạo file bat để biên dịch:

;------------------------------------------------------------------------------
@echo off
 
if exist %1.obj del %1.obj
if exist %1.exe del %1.exe
 
: -----------------------------------------
: assemble *.asm into an OBJ file
: -----------------------------------------
 
C:\tasm32\bin\TASM32.EXE  /ml /z /m9 /q  %1.asm
 
if errorlevel 1 goto errasm
 
: -----------------------
: link the main OBJ file
: -----------------------
 
c:\tasm32\bin\tlink32  /Tpd /aa /c /x  %1.obj,,,c:\tasm32\importlib\import32.lib,%1.def
 
if errorlevel 1 goto errlink
 
;----------------------------
;pewrite
;---------------------------
 
c:\tasm32\tasm32\pewrite %1.exe
 
if errorlevel 1 goto errpewrite
 
goto TheEnd
 
:errlink
 
: ----------------------------------------------------
: display message if there is an error during linking
: ----------------------------------------------------
 
echo.
echo There has been an error while linking this project.
echo.
goto TheEnd
 
:errasm
 
: -----------------------------------------------------
: display message if there is an error during assembly
: -----------------------------------------------------
 
echo.
echo There has been an error while assembling this project.
echo.
 
goto TheEnd
 
: -----------------------------------------------------
: display message if there is an error during pewrite
: -----------------------------------------------------
 
:errpewrite
 
echo.
echo There has been an error while pewrite this project.
echo.
 
goto TheEnd
 
:TheEnd
 
:if exist %1.obj del %1.obj
 
pause
 
;----------------------------------------------------------

Ví dụ cụ thể:

a/dll.asm như sau:

   1:                  .586p
   2:                          .model  flat, stdcall
   3:                          locals
   4:                          jumps
   5:                       
   6:  include                 dll.inc
   7:   
   8:                          .data
   9:   
  10:   msg_title   DB "Dll title",0
  11:   msg_message DB "Hello World! dll loader",0
  12:   msg_message_func DB "dll func loader",0
  13:   
  14:   
  15:   
  16:                          .code
  17:  ;dllmain, entrypoint dll
  18:  start                   proc
  19:                          arg     imagebase
  20:                          arg     reason
  21:                          arg     reserved
  22:                          
  23:                          pushad                       
  24:                          cmp     reason, 1
  25:                          jne     __e_dllinit
  26:   
  27:                  ;(code here)
  28:          push 0
  29:          push offset msg_title
  30:          push offset msg_message
  31:          push 0
  32:          call MessageBoxA
  33:   
  34:  __e_dllinit:            popad
  35:                          mov     eax, 1
  36:                          leave
  37:                          retn    0ch
  38:                          endp
  39:  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                        
  40:  public myFunction
  41:   
  42:  myFunction PROC
  43:          push 0
  44:          push offset msg_title
  45:          push offset msg_message_func
  46:          push 0
  47:          call MessageBoxA
  48:       ret
  49:  myFunction ENDP
  50:   
  51:  end     start

b/dll.inc như sau:

extrn ExitProcess:proc
extrn MessageBoxA:proc

c/dll.def như sau:

EXPORTS
myFunction

d/Loader gọi hàm trong dll như sau:

Phần loader này ko kiểm tra giá trị trả về của các APIs:

   1:                          .586p
   2:                          .model  flat
   3:                          locals
   4:                          jumps
   5:                          
   6:  extrn ExitProcess:proc
   7:  extrn MessageBoxA:proc
   8:  extrn LoadLibraryA:proc
   9:  extrn GetProcAddress:proc
  10:   
  11:   
  12:  o    equ     offset
  13:   
  14:  .data
  15:   
  16:      msg_title   DB "MessageBox title",0
  17:      msg_message DB "Hello World!",0
  18:   
  19:      dllname db "dll.DLL",0
  20:      dllfunc db "myFunction",0
  21:   
  22:      hlib dd ?
  23:      fn_myFunction dd ?
  24:   
  25:  .code
  26:  start:                 
  27:   
  28:          push 0
  29:          push offset msg_title
  30:          push offset msg_message
  31:          push 0
  32:          call MessageBoxA
  33:   
  34:          push o dllname
  35:          call LoadLibraryA
  36:          mov hlib,eax
  37:   
  38:   
  39:          push o dllfunc
  40:          push hlib
  41:          call GetProcAddress
  42:          mov fn_myFunction,eax
  43:   
  44:          call fn_myFunction
  45:   
  46:          push 0
  47:          call ExitProcess
  48:   
  49:   end     start