大理寺少卿 发表于 2024-12-25 22:19:47

Win32汇编学习笔记04.重定位与汇编引擎

### 重定位

**重定位:**也称为代码自重定位,代码自己去计算自己使用的各种资源再新进程中的地址,相应代码被称为被重新定位过后的代码。

#### 示例

- 目标:向指定进程 扫雷 注入一段机器码,机器码的作用是弹出MessageBox。

```
与远程注入dll的区别:原是加载dll,本目标是注入一段机器码。
```


注机器码就是 把机器码写到对应进程里面去,写的地方不能覆盖它原本代码,否则会影响它原本的功能 ,可以去找一些空隙,但是这种方法不是很通用.最好的办法是 申请一块内存,把代码写进去,在调用线程去跑这个段代码

#### .asm

```
.586
.model flat,stdcall
option casemap:none

   include windows.inc
   include user32.inc
   include kernel32.inc
   
   includelib user32.lib
   includelib kernel32.lib


WinMain proto

.data

   g_szCap    db "扫雷",0          ;窗口标题,用来获取窗口句柄
   g_szTitledb "温情提示",0      ;弹窗窗口标题
   g_szText   db "你被注入了!!!",0 ;弹窗内容
.code

CODE_BEGIN:
invoke MessageBox,NULL,offsetg_szText,offset g_szTitle,MB_OK


; ---------------------------------------------------------------------------
WinMain proc
        LOCAL @hWndWinMine :HWND    ;窗口句柄
        LOCAL @dwPid :HWND          ;进程id
        LOCAL @hProc :HINSTANCE   ;进程句柄
        LOCAL @pAddr :LPVOID      ;申请的内存地址
        LOCAL @dwBytesWirites :DWORD    ;写入的字节数

        invoke FindWindow,NULL ,offset g_szCap;通过窗口标题获取窗口句柄
    mov    @hWndWinMine,eax
      
    invoke GetWindowThreadProcessId,@hWndWinMine,addr @dwPid;获取进程id
      
    invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,@dwPid   ;获取进程句柄
    mov   @hProc,eax
      
    invoke VirtualAllocEx,@hProc, NULL,1,MEM_COMMIT,PAGE_EXECUTE_READWRITE    ;自动申请内存空间
    mov   @pAddr,eax
      
    ;在内存中写入代码
    invoke WriteProcessMemory,@hProc,@pAddr,\      ;\是换行
       offset CODE_BEGIN, offset WinMain -   offset CODE_BEGIN,\
      addr @dwBytesWirites
         
    invoke CreateRemoteThread,@hProc ,NULL,0,@pAddr,NULL,0,NULL;创建线程
      
        mov   eax,0
        ret
WinMain endp

start:


        invoke WinMain
        invoke ExitProcess,eax

end start
```

没重定向之前运行程序,发现我么的文件和扫雷都崩了,单独调试我们自己的代码是没问题,所以需要同时调试2个进程

!(./notesimg/1653393343631-871040dd-9b2b-4884-9dfa-b046997d0d7a.png)

写入代码的地址是 05790000

!(./notesimg/1653393465032-ef4d84f1-b4bf-4d09-8241-5e7fc9c3ee0f.png)

!(./notesimg/1653393582478-665af852-8309-4d00-9c8f-85e60d68aec7.png)

可以看出,我们字符串的内存地址获取失败了,因为我们的字符串写在了我们的自己程序中,并不在扫雷程序中

把字符串移进来,调试发现地址还是我们自己的地址,字符串地址需要调整,最好让他自己算.我们只要原来代码所在的地址,与新地址所在的差值,就可以推算出新字符串所在的地址

!(./notesimg/1653394365268-baa15add-b60b-4393-9b0a-ea0b969261b6.png)

```
.586
.model flat,stdcall
option casemap:none

   include windows.inc
   include user32.inc
   include kernel32.inc
   
   includelib user32.lib
   includelib kernel32.lib


WinMain proto


.data

   g_szCap    db "扫雷",0          ;窗口标题,用来获取窗口句柄

.code

CODE_BEGIN:

jmp MSGBOX
g_szTitledb "温情提示",0      ;弹窗窗口标题
g_szText   db "你被注入了!!!",0 ;弹窗内容

MSGBOX:
   call LTEST;会把LIST 的地址入站   

LTEST:
   pop ebx                ;获取 LTEST 在新进程的地址
   sub ebx ,offset LTEST;可以得到LTEST 在 新进程地址和我们自己进程的地址差值
   
   push MB_OK
   
   mov eax, offsetg_szTitle;获取字符串在原进程中的地址
   add eax, ebx   ;获取字符串在新进程中的地址
   push eax         ;入栈
   
   
   mov eax, offsetg_szText
   add eax, ebx
   push eax
   
   push NULL
   
   callMessageBox
   
;invoke MessageBox,NULL,offsetg_szText,offset g_szTitle,MB_OK
ret


; ---------------------------------------------------------------------------
WinMain proc
        LOCAL @hWndWinMine :HWND    ;窗口句柄
        LOCAL @dwPid :HWND    ;进程id
        LOCAL @hProc :HINSTANCE    ;线程句柄
        LOCAL @pAddr :LPVOID    ;申请的内存地址
        LOCAL @dwBytesWirites :DWORD    ;写入的字节数

        invoke FindWindow,NULL ,offset g_szCap;通过窗口标题获取窗口句柄
      mov    @hWndWinMine,eax
      
      invoke GetWindowThreadProcessId,@hWndWinMine,addr @dwPid;获取进程id
      
      invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,@dwPid   ;创建新线程
      mov   @hProc,eax
      
      invoke VirtualAllocEx,@hProc, NULL,1,MEM_COMMIT,PAGE_EXECUTE_READWRITE    ;自动申请内存空间
      mov   @pAddr,eax
      
      ;在内存中写入代码
      invoke WriteProcessMemory,@hProc,@pAddr,\      ;\是换行
         offset CODE_BEGIN, offset WinMain -   offset CODE_BEGIN,\
         addr @dwBytesWirites
         
      invoke CreateRemoteThread,@hProc ,NULL,0,@pAddr,NULL,0,NULL
      
        mov   eax,0
        ret
WinMain endp

start:

        invoke WinMain
        invoke ExitProcess,eax

end start

```

再继续调试,发现此数地址已经变了

!(./notesimg/1653399216247-40e382b8-1c6c-4d3f-8da1-507a69f516ec.png)

有时候 CTRL + G 找地址会提示无效地址, 可以先到内存窗口,右键,在cpu数据窗口中查看,找到自己跳转的地址,在回到 代码页面用 CTRL + G跟随就可以了

!(./notesimg/1653399131094-bd46a4fb-89d5-4818-b3aa-2e199322cbda.png)

user32在 同一台电脑上的 不同进程的地址是一样的,因此可以利用这一点,还要注意,我们写的代码位于代码段,必须修改才能写入

重定位后的代码

```
.586
.model flat,stdcall
option casemap:none

   include windows.inc
   include user32.inc
   include kernel32.inc
   
   includelib user32.lib
   includelib kernel32.lib


WinMain proto


.data

   g_szCap    db "扫雷",0          ;窗口标题,用来获取窗口句柄
   g_szUser32 db "user32", 0
   g_szMessageBox db "MessageBoxA", 0


.code

CODE_BEGIN:

jmp MSGBOX
g_szTitledb "温情提示",0      ;弹窗窗口标题
g_szText   db "你被注入了!!!",0 ;弹窗内容
g_dwMessageBox   dd 0         ;MessageBox的地址

MSGBOX:


   ;下面四条就是重定位的核心代码
   call NEXT;会把LIST 的地址入站   
NEXT:
   pop ebx                ;获取 NEXT 在新进程的地址
   sub ebx ,offset NEXT;可以得到NEXT 在 新进程地址和我们自己进程的地址差值
   
   

   push MB_OK
   
   mov eax, offsetg_szTitle;获取字符串在原进程中的地址
   add eax, ebx   ;获取字符串在新进程中的地址
   push eax         ;入栈
   
   
   mov eax, offsetg_szText
   add eax, ebx
   push eax
   
   push NULL
   
   mov eax, offset g_dwMessageBox
   add eax, ebx
   mov eax,
   call eax
   
   ;callMessageBox
   
   ;invoke MessageBox,NULL,offsetg_szText,offset g_szTitle,MB_OK
ret


; ---------------------------------------------------------------------------
WinMain proc
        LOCAL @hWndWinMine :HWND    ;窗口句柄
        LOCAL @dwPid :HWND    ;进程id
        LOCAL @hProc :HINSTANCE    ;线程句柄
        LOCAL @pAddr :LPVOID    ;申请的内存地址
        LOCAL @dwBytesWirites :DWORD    ;写入的字节数
        LOCAL @dwOldProc:DWORD    ;之前的内存属性

        invoke FindWindow,NULL ,offset g_szCap;通过窗口标题获取窗口句柄
      mov    @hWndWinMine,eax
      
      invoke GetWindowThreadProcessId,@hWndWinMine,addr @dwPid;获取进程id
      
      invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,@dwPid   ;创建新线程
      mov   @hProc,eax
      
      invoke VirtualAllocEx,@hProc, NULL,1,MEM_COMMIT,PAGE_EXECUTE_READWRITE    ;自动申请内存空间
      mov   @pAddr,eax
      
      
         ;修改代码区内存属性
      invoke VirtualProtect, offset CODE_BEGIN, 1, PAGE_EXECUTE_READWRITE, addr @dwOldProc

      invoke GetModuleHandle, offset g_szUser32
      invoke GetProcAddress, eax, offset g_szMessageBox
      
      mov g_dwMessageBox, eax

      ;还原内存属性
      invoke VirtualProtect, offset CODE_BEGIN, 1, @dwOldProc, addr @dwOldProc

         
      ;在内存中写入代码
      invoke WriteProcessMemory,@hProc,@pAddr,\      ;\是换行
         offset CODE_BEGIN, offset WinMain -   offset CODE_BEGIN,\
         addr @dwBytesWirites
         
      invoke CreateRemoteThread,@hProc ,NULL,0,@pAddr,NULL,0,NULL
      
        mov   eax,0
        ret
WinMain endp

start:

        invoke WinMain
        invoke ExitProcess,eax

end start
```

汇编引擎

使用 XDE

库: 如果装了x32DEBUG ,那么就有需要的库

!(./notesimg/1653401584381-b3aaeb73-db09-45f1-8906-52343ff44741.png)用C来实现 汇编引擎

创建一个控制台程序

把头文件,dll,lib 拷贝到项目

!(./notesimg/1653402030538-3fdb60a9-9349-496f-8db9-0207e056ee43.png)

成员:

132位还是64位,true64位 flase 32位

2 汇编的地址   (跳转类指令必须)

3返回参数,汇编出来的机器码有几个字节

4回调,用不上,空就行

5传出的机器吗

6我们写进去的源码

7错误信息

```
// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>

#include "XEDParse.h"
#pragma comment (lib, "XEDParse_x86.lib")

int main()
{
    XEDPARSE xde = {};
    xde.x64 = false;
    xde.cip = 0x00401000;
    strcpy_s(xde.instr, sizeof(xde.instr), "mov eax, eax");

    XEDPARSE_STATUS stus = XEDParseAssemble(&xde);

    std::cout << "Hello World!\n";
}
```

#### 汇编实现汇编引擎

```
.586
.model flat,stdcall
option casemap:none

   include windows.inc
   include user32.inc
   include kernel32.inc
   include msvcrt.inc
   
   include AsmXde.inc
   
   includelib user32.lib
   includelib kernel32.lib
   includelib msvcrt.lib
   
   includelib XEDParse_x86.lib

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD

.data


   xdep XEDPARSE <FALSE, 00401000h>   
   g_szInstr db "mov ebp, esp", 0

.code
start:
    invoke crt_strcpy, offset xdep._instr, offset g_szInstr
    invoke XEDParseAssemble, offset xdep

end start
```

.inc

```
ifndef XDE_INC
XDE_INCequ 1

XEDPARSE_ERROR equ 0
XEDPARSE_OK equ 1

XEDPARSE_MAXBUFSIZE equ 256
XEDPARSE_MAXASMSIZE equ 16

;定义结构体
XEDPARSE struc
    x64 db 0
    ALIGN 8   ;设置对齐值
    cip dd 0;只用低32位
      dd 0
    dest_size dd 0
    cbUnknown dd 0
    dest db XEDPARSE_MAXASMSIZE dup(0)
    _instr db XEDPARSE_MAXBUFSIZE dup(0)
    error db XEDPARSE_MAXBUFSIZE dup(0)
XEDPARSE ends

XEDParseAssemble proto c :ptr XEDPARSE   ;函数声明

endif
```

!(./notesimg/1653404208476-39da2bc2-68e1-40b8-b10e-a9c5b092acac.png)

!(./notesimg/1653404239396-a7407c69-0abc-4f8b-842a-31925ce05393.png)

!(./notesimg/1653403959054-17c7de61-e42f-409e-9daf-54ac6a120325.png)

比较强悍的工具是:Asmjit   但只能c使用

### 作业

周作业

#### 1. 代码注入器

有bug,   eip 每次要加它的长度

头文件xde.inc

```
ifndef XDE_INC
XDE_INC equ 1 ;防止重复包含


    ;这是原先出错或成功的枚举,换成equ
    XEDPARSE_ERROR equ 0
    XEDPARSE_OK equ 1


    ;原先的宏
    XEDPARSE_MAXBUFSIZEequ 256
    XEDPARSE_MAXASMSIZE equ 16


    ;定义结构体 还需要设置对齐值,它的对齐值是8
    XEDPARSE struc
      x64       db 0 ;x64
      ALIGN   8 ;设置对齐值,只影响它下一条
      cip       dd 0 ;它是__int64类型的,但是我们只用低32位,所以就dd ,高32位就不用了
                  dd 0 ;它的高32位
      dest_size dd 0;传出参数,机器码有几个字节
      cbUnknown dd 0;回调
      dest      db XEDPARSE_MAXASMSIZE dup(0) ;机器码
      _instr   db XEDPARSE_MAXBUFSIZE dup(0);汇编指令
      error   db XEDPARSE_MAXBUFSIZE dup(0)
         
    XEDPARSE ends

    ;函数声明,C调用约定 ,参数为结构体指针
    XEDParseAssemble proto C :ptr XEDPARSE

endif
```

code.inc

```
include windows.inc
include kernel32.inc
include user32.inc
include Comctl32.inc
include shell32.inc
include msvcrt.inc
include Xde.inc

includelib kernel32.lib
includelib user32.lib
includelib Comctl32.lib
includelib shell32.lib
includelib msvcrt.lib
includelib XEDParse_x86.lib

DlgProc                        PROTO        :HWND,:UINT,:WPARAM,:LPARAM

.const

IDD_DIALOG1                        equ 101
BTN_SELECT          equ 1001
BTN_INJECTION       equ 1002
EDT_PROCESSID       equ 1003
EDT_CODE            equ 1004


DLG_PROCESS         equ 1000
LST_PROCESS         equ 1005


;#########################################################################

.data?

hInstance                        dd ?

;#########################################################################

```

code.asm

```
.386
.model flat, stdcall;32 bit memory model
option casemap :none;case sensitive

include CodeIn.inc

.data
    g_szHintProcessID db "进程ID" , 0 ;提示的中文
    g_szHintProcessName db "进程名" , 0 ;提示的中文
    g_szFmt db "%d",0 ;格式化字符串
    g_szProcess db 255 dup(0) ; 进程ID字符串
    g_hWnd dd 0 ;主窗口句柄
    g_szCode db 255 dup(0)
.code


;获取进程信息
GetProcess proc hWin:HWND
    LOCAL lvcol:LVCOLUMN ;lst的列结构体
    LOCAL item:LVITEM;项的结构体
    local hlist
    LOCAL pe32:PROCESSENTRY32 ;pe32
    LOCAL hProcessSnap:HANDLE
    LOCAL bRet:BOOL ; bool类型的返回值
    LOCAL nRowCount:dword;列数
    LOCAL szTh32ProcessID:byte
    LOCAL oldStyle :dword

    ;先初始化list控件
    invoke GetDlgItem,hWin,LST_PROCESS;获取控件句柄
    mov hlist,eax

    ;向样式结构体里填数据
    mov lvcol.imask,LVCF_FMT or LVCF_WIDTH orLVCF_TEXT or LVCF_SUBITEM
    mov lvcol.fmt,LVCFMT_CENTER
    mov lvcol.lx,275
    mov lvcol.pszText,offset g_szHintProcessID
    ;发消息,增加一列
    ;invoke SendMessage,hlist,LVM_INSERTCOLUMN,0,addr lvcol
    invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_INSERTCOLUMN,0,addr lvcol

    ;第二列
    mov lvcol.pszText,offset g_szHintProcessName
    ;invoke SendMessage,hlist,LVM_INSERTCOLUMN,1,addr lvcol
   invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_INSERTCOLUMN,1,addr lvcol


    ;开始获取进程
    ;hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
    invoke CreateToolhelp32Snapshot,TH32CS_SNAPALL,0
    mov hProcessSnap,eax

    ;Process32First(hProcessSnap, &pe32)
    mov pe32.dwSize,size PROCESSENTRY32
    invoke Process32First,hProcessSnap,addr pe32
    mov bRet,eax

    ;First成功后循环
    .if bRet != 0
         ;列数先置为0
      mov nRowCount ,0
      ;开始循环
      .REPEAT
                        ;插入第一列
                mov eax,nRowCount
                        mov item.iItem , eax; ;行号 从0开始
                        mov item.iSubItem,0 ;列号
                      mov item.imask,LVCF_FMT or LVCF_WIDTH or LVCF_TEXT
                        mov eax,pe32.th32ProcessID
                        ;格式化字符串进程ID
                        invoke wsprintf,addr szTh32ProcessID,offset g_szFmt, pe32.th32ProcessID
                        lea eax,szTh32ProcessID
                        mov item.pszText,eax

                        invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_INSERTITEM,0,addr item
                  
                     
                ;清除内存
                invoke crt_memset,addr item,0,size item
                     
                        ;插入第二列
                        mov eax,nRowCount
                        mov item.iItem , eax; ;行号
                        mov item.iSubItem,1;列号
                        mov item.imask , LVCF_FMT or LVCF_WIDTH or LVCF_TEXT;
                        lea eax,pe32.szExeFile ;进程名称
                        mov item.pszText,eax
                     
                     
                        ;插入其他列
                        invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_SETITEMTEXT,nRowCount,addr item
                     
                ;行号++
                mov eax,nRowCount
                inc eax
                mov nRowCount,eax
            
                ;清除内存
                lea eax, pe32
                invoke crt_memset,eax,0,128
                ;重新赋值大小
                mov pe32.dwSize,size PROCESSENTRY32
            
                ;Next获取下一个
                        invoke Process32Next,hProcessSnap,addr pe32
                mov bRet,eax
       .UNTIL bRet == 0
    .endif


    ;获取旧样式
    invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_GETEXTENDEDLISTVIEWSTYLE,0,0
    ;拼接新样式
    or eax,LVS_EX_FULLROWSELECT
    or eax,LVS_EX_GRIDLINES

    ;设置选中高亮一行和网格线样式
    invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_SETEXTENDEDLISTVIEWSTYLE,0,eax
    ret

GetProcess endp


OnProc proc hWin:HWND,wParam:WPARAM,lParam :LPARAM
    LOCAL item:LVITEM;项的结构体
    LOCAL dwSel:dword
    ;判断控件ID
    mov eax,wParam
    .if eax == LST_PROCESS
      mov esi,lParam
      assume esi:ptr NMHDR
      mov ebx,.code
      assume esi:nothing
      .if ebx == NM_DBLCLK
            ;invoke MessageBox,hWin,offset g_szHintProcessID,offset g_szHintProcessID,MB_OK
            ;获取选中的ID
            invoke SendDlgItemMessage ,hWin,LST_PROCESS,LVM_GETSELECTIONMARK,0,0
         
            ;选中ID赋值
            mov dwSel,eax
         
            ;开始获取选中的文本
                mov item.iItem , eax; ;行号
                mov item.iSubItem,0;列号
                mov item.imask , LVCF_FMT or LVCF_WIDTH or LVCF_TEXT;
            lea eax,g_szProcess
            mov item.pszText,eax
            mov item.cchTextMax,size g_szProcess
            invoke SendDlgItemMessage,hWin,LST_PROCESS,LVM_GETITEMTEXT,dwSel,addr item
         
         
            ;给外面的进程文本框赋值
            invoke        SetDlgItemText,g_hWnd,EDT_PROCESSID,offset g_szProcess
            ;关闭窗口
            invoke EndDialog,hWin,0
      .endif
    .endif
   
   
   
   
    ret

OnProc endp
;进程对话框过程函数
DlgProcessProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
      mov                eax,uMsg
        .if eax==WM_INITDIALOG ;初始化
      invoke GetProcess,hWin
        .elseif eax==WM_CLOSE
                invoke EndDialog,hWin,0
    .elseif eax == WM_NOTIFY
      invoke OnProc,hWin,wParam,lParam
        .else
                mov                eax,FALSE
                ret
        .endif
        mov                eax,TRUE
        ret

DlgProcessProc endp

Inject proc
    LOCAL @hProc:HINSTANCE ; 进程句柄
    LOCAL @pAddr :LPVOID ;申请的内存地址
    LOCAL @dwBytesWrited:dword ;写入的字节数,它是返回值
    LOCAL @dwOldProc:dword ;旧的内存属性
    LOCAL @xdep:XEDPARSE
    LOCAL @machineCode:byte ;字符串
    LOCAL @StrLen :dword
    LOCAL @idx:dword

   ;把进程ID字符串转成数字
    invoke crt_atoi,offset g_szProcess
    ; 打开进程
    invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,eax
    ;把进程句柄存储一下
    mov @hProc,eax
    ;申请内存
    invoke VirtualAllocEx,@hProc,NULL,1,MEM_COMMIT,PAGE_EXECUTE_READWRITE
    ;把申请的内存地址存一下
    mov @pAddr,eax

    ;解析指令


    ;代码注入

    ;获取指令长度
    invoke crt_strlen,offset g_szCode
    mov @StrLen,eax

    ;一个字节一个字节读取
    lea esi,g_szCode
    lea edi,@machineCode


    .WHILE @StrLen > 0
      mov eax,@idx
      .if byte ptr == 0dh
            inc esi
         
            .continue
      .endif
      .if byte ptr == 0ah
            inc esi
         ;开始注入代码
            mov @xdep.x64,FALSE ;64位
            mov eax,@pAddr
            mov @xdep.cip,eax   ;内存地址
            ;拷贝指令
            invoke crt_strcpy ,addr @xdep._instr,addr @machineCode
            invoke XEDParseAssemble,addr @xdep
         
            ;要加上机器码的长度,也就是写入的字节数,确保下次正确写入
            mov eax,@pAddr
            add eax,@dwBytesWrited
            mov @pAddr,eax
            ;写入机器码
            invoke WriteProcessMemory,@hProc,@pAddr,addr @xdep.dest,@xdep.dest_size,addr @dwBytesWrited
         
            ;edi恢复
            lea edi,@machineCode
            invoke crt_memset,addr @machineCode,0,255
            ;invoke crt_memset, @xdep, 0,255
            invoke crt_memset,addr @xdep._instr,0,255
            invoke crt_memset,addr @xdep.dest,0,16
            .continue
      .endif
      ;读取一个字节
      movsb
      ;长度--
      sub @StrLen,1
      
    .ENDW

    ;创建远程线程 它的地址就是申请的内存地址,那块内存已经写入了自己的代码了
    invoke CreateRemoteThread,@hProc,NULL,0,@pAddr,NULL,0,NULL
    ret

Inject endp
start:

        invoke GetModuleHandle,NULL
        mov                hInstance,eax

    invoke InitCommonControls
        invoke DialogBoxParam,hInstance,IDD_DIALOG1,NULL,addr DlgProc,NULL
        invoke ExitProcess,0

;########################################################################

; 主对话框过程函数
DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
    mov eax,hWin
    mov g_hWnd,eax

        mov                eax,uMsg
        .if eax==WM_INITDIALOG ;初始化

        .elseif eax==WM_COMMAND
             mov eax,wParam
         .if ax == BTN_SELECT   ;打开对话框选择进程
               invoke CreateDialogParam,hInstance,DLG_PROCESS,NULL,addr DlgProcessProc,NULL
         .elseif ax == BTN_INJECTION;代码注入
               ;获取输入的代码
               invoke GetDlgItemText,hWin,EDT_CODE,offset g_szCode,255
               invoke Inject
            
               ;解析输入的代码
         .endif
        .elseif eax==WM_CLOSE
                invoke EndDialog,hWin,0
        .else
                mov                eax,FALSE
                ret
        .endif
        mov                eax,TRUE
```

资源界面

!(./notesimg/1653969809236-52346ef1-8f92-41a5-bd74-595ac1c6f08d.png)

!(./notesimg/1653969922912-965b6645-4777-45b4-9fc3-14942e798100.png)

#### 2. 扫雷辅助

C++版

```
#include <Windows.h>
#include <Windowsx.h>

#define ARY_0 0x1005340
#define MINE 0x8F

HWND g_hWnd = 0;
WNDPROC g_OldProc = 0;

LRESULT CALLBACK WindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch (Msg)
    {
    case WM_MOUSEMOVE:
    {
      int x = LOWORD(lParam);
      int y = HIWORD(lParam);

      int ary_x = (x + 4) >> 4;
      int ary_y = ((y - 0x27) >> 4) << 5;

      if (*(PBYTE)((DWORD)ARY_0 + ary_x + ary_y) == MINE)
      {
            SetWindowText(hWnd, "扫雪");
      }
      else
      {
            SetWindowText(hWnd, "扫雷");
      }
    }

    default:
      break;
    }

    return CallWindowProc(g_OldProc, hWnd, Msg, wParam, lParam);
}


void Init()
{
    g_hWnd = ::FindWindow(NULL, "扫雷");
        g_OldProc = (WNDPROC)SetWindowLong(g_hWnd, GWL_WNDPROC, (LONG)WindowProc);
}


BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    {
      Init();
      break;
    }
    }
    return TRUE;
}
```

win32asm版

```
.386
.model flat, stdcall
option casemap :none

include WinMineDLL.Inc


.data
    g_szBuffSnow db "扫雪", 0
    g_szBuffMine db "扫雷", 0
    g_szBuffError db "SetWindowLong success", 0
    g_szBuffX db "X", 0
    g_szBuffY db "Y", 0
   
    g_OldProc dd 0
    g_ddMine dd 0
    g_hMine dd 0


.code


MYWindowProc proc uses ecx esi edi, hwnd:HWND, uMsg:UINT , wParam:WPARAM, lParam:LPARAM

    .if uMsg == WM_MOUSEMOVE

      ; coordinate -> ary
      mov eax, dword ptr
      shr eax, 010h
      sub eax, 027h
      sar eax, 04h
      mov edi, eax
      shl edi, 5 ; edi - Y
      
      movzx eax, word ptr
      add eax, 4h
      sar eax, 4h
      mov esi, eax ; esi - X
      
      ; ary = 01005340h
      xor eax, eax
      mov ebx, 01005340h
      add ebx, esi
      add ebx, edi
      mov al, byte ptr
      
      ; is mine
      mov g_ddMine, eax
      .if g_ddMine == 08Fh
            invoke SetWindowText, hwnd, offset g_szBuffSnow
      .elseif
            invoke SetWindowText, hwnd, offset g_szBuffMine
      .endif
    .endif

    invoke CallWindowProc, g_OldProc, hwnd, uMsg, wParam, lParam

    ret
MYWindowProc endp


InitDLL proc

      invoke FindWindow, NULL, offset g_szBuffMine
      mov g_hMine, eax

      invoke SetWindowLongW, g_hMine, GWL_WNDPROC, offset MYWindowProc
      mov g_OldProc, eax

      .if g_OldProc != NULL
            invoke MessageBox, NULL, offset g_szBuffError, NULL, MB_OK
      .endif
      
InitDLL endp


DllMain proc hinstDLL:HINSTANCE, fdwReason:DWORD, lpvReserved:LPVOID

    .if fdwReason == DLL_PROCESS_ATTACH
      invoke InitDLL
    .endif

    mov eax, TRUE
    ret
DllMain endp

end DllMain
```

```
.386
.model flat, stdcall
option casemap:none

include windows.inc
include user32.inc
include kernel32.inc

includelib user32.lib
includelib kernel32.lib

.data
    g_hwnd HWND 0
    g_windowtitle db "扫雷", 0
    g_dProcessId dd 0
    g_dThreadId dd 0
    g_hHook HHOOK 0

    g_sz db "钩子", 0

.code
GetMessageProc proc nCode:dword, wParam:WPARAM, lParam:LPARAM

    .if nCode < 0
      invoke CallNextHookEx, g_hHook, nCode, wParam, lParam
                ret

        .endif

    mov eax, lParam
    assume eax:ptr MSG


    .if .message == WM_COMMAND
      invoke MessageBox, NULL, offset g_sz, offset g_sz, MB_OK
    .endif


    invoke CallNextHookEx, g_hHook, nCode, wParam, lParam
    ret
GetMessageProc endp


DllMain proc hinstDLL:HINSTANCE, fdwReason:DWORD, lpvReserved:LPVOID
    ;给扫雷安装消息钩子
    invoke FindWindow, offset g_windowtitle, NULL
    mov g_hwnd, eax
    invoke GetWindowThreadProcessId, g_hwnd, offset g_dProcessId
        mov g_dThreadId, eax
    invoke SetWindowsHookEx, WH_GETMESSAGE, GetMessageProc, NULL, g_dThreadId

    ret

DllMain endp

end DllMain
```
页: [1]
查看完整版本: Win32汇编学习笔记04.重定位与汇编引擎