x86汇编实现一个注入器
Posted 不会写代码的丝丽
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了x86汇编实现一个注入器相关的知识,希望对你有一定的参考价值。
概述
我们实现如下的功能:
遍历所有win32程序,让其选中一个程序,用户自行输入注入的汇编代码然后执行
汇编解析器
假设我们有call 00401000
当前ip在0040000
处,那么请给出这个语句机器码.
我们这里直接使用一个开源库XedParse
.来实现这个功能
XedParse
我们下载后可能得到文件夹如下:
由于我们使用汇编实现因此对于XEDParse.h
这个文件我们需要转化为对应的汇编头文件XEDParse.inc
这里我们给出一个版本
;XEDParse.inc
ifndef _XEDPARSE_H
_XEDPARSE_H equ 0
include windows.inc
XEDPARSE_MAXBUFSIZE equ 256
XEDPARSE_MAXASMSIZE equ 16
XEDPARSE_ERROR equ 0
XEDPARSE_OK equ 1
XEDPARSE struc 8
x64 dd 0; // use 64-bit instructions 是否为64位
cip dq 0; //instruction pointer (for relative addressing) 当前指令的ip,将汇编转化为机器码时当前ip会影响到结果
dest_size dd 0; //destination size (returned by XEDParse) 解析后目标机器码的大小
cbUnknown dd 0; //unknown operand callback 错误回调
dest db XEDPARSE_MAXASMSIZE dup(0); //destination buffer 解析后的机器码
instr_ db XEDPARSE_MAXBUFSIZE dup(0); //instruction text 需要解析的指令
error db XEDPARSE_MAXBUFSIZE dup(0); //error text (in case of an error) 错误文本
XEDPARSE ends
;一个解析函数会调用dll中的实验
XEDParseAssemble proto C XEDParse:DWORD
includelib XEDParse_x86.lib
endif
相关UI逻辑
这里我们单独使用一个汇编文件实现插入item
到listview
中,由于比较简单所以不做过多解释,都是win32
的基础语法
.386
.model flat, stdcall ;32 bit memory model
option casemap :none ;case sensitive
include windows.inc
include msvcrt.inc
includelib msvcrt.lib
include user32.inc
.code
;函数:::::给listview插入列
InsertColum proc hWnd:HWND,dwCol:DWORD,szTitle:LPSTR,dwWith:DWORD
LOCAL @lvc:LVCOLUMN
;内存重置
invoke crt_memset,addr @lvc,0,type @lvc
mov @lvc.imask,LVCF_FMT or LVCF_TEXT or LVCF_WIDTH
;左对齐
mov @lvc.fmt,LVCFMT_LEFT
;指定宽度
push dwWith
pop @lvc.lx
;标题
push szTitle
pop @lvc.pszText
;发送信息插入列
invoke SendMessage,hWnd,LVM_INSERTCOLUMN,dwCol, addr @lvc
ret
InsertColum endp
;函数:::::给listview插入每个item
InsertItem proc hWnd:HWND,szTitle:LPSTR,dwUserData:DWORD
LOCAL @li:LVITEM
invoke crt_memset,addr @li,0,type @li
mov @li.imask, LVIF_TEXT OR LVIF_PARAM
push szTitle
pop @li.pszText
push dwUserData
pop @li.lParam
;插入一个条目
invoke SendMessage,hWnd,LVM_INSERTITEM,0,addr @li
ret
InsertItem endp
;函数:::::给listview 某个item 设置文本
SetIemText proc hWnd:HWND,dwRow:DWORD,dwCol:DWORD,szTitle:LPSTR
LOCAL @li:LVITEM
invoke crt_memset,addr @li,0,type @li
mov @li.imask, LVIF_TEXT
;指定行
push dwRow
pop @li.iItem
;指定列
push dwCol
pop @li.iSubItem
push szTitle
pop @li.pszText
invoke SendMessage,hWnd,LVM_SETITEMTEXT,0,addr @li
ret
SetIemText endp
end
遍历所有程序
这里我们利用CreateToolhelp32Snapshot
即可遍历出所有程序,这里可能回踩坑亲。可以看最后一节
Refresh proc hLstv:HWND
LOCAL @hSnap:HANDLE
LOCAL @pe32:PROCESSENTRY32
LOCAL @szBuff[32]:BYTE
invoke SendMessage,hLstv,LVM_DELETEALLITEMS ,0, 0
invoke RtlZeroMemory,addr @pe32,type @pe32
mov @pe32.dwSize,type @pe32
;捕获进程快照
invoke CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS,0
mov @hSnap,eax
;遍历快照的程序
invoke Process32First , @hSnap,addr @pe32
.if eax !=0
.repeat
invoke wsprintf,addr @szBuff,offset g_szFmt,@pe32.th32ProcessID
;插入行
invoke InsertItem,hLstv,addr @szBuff,@pe32.th32ProcessID
;设置文本
invoke SetIemText,hLstv,0,1,addr @pe32.szExeFile
invoke Process32Next,@hSnap,addr @pe32
.until eax==0
.endif
ret
Refresh endp
注入代码
Inject proc dwPid:DWORD,hDlg:HWND
LOCAL @hProc:HWND
LOCAL @lpAddr:LPVOID
LOCAL @dwBytesWrited:DWORD
;得到进程句柄并获取所有权限
invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,dwPid
;保存进程句柄
mov @hProc,eax
;申请内存
invoke VirtualAllocEx,@hProc,NULL,1000h,MEM_COMMIT,PAGE_EXECUTE_READWRITE
;保存内存引用
mov @lpAddr,eax
;Assembly函数用于解析用户输入的汇编转化为机器码输入到g_aryOpcodeBuf
invoke Assembly,@lpAddr,hDlg
.if eax==FALSE
ret
.endif
;内存写入
invoke WriteProcessMemory,@hProc,@lpAddr,offset g_aryOpcodeBuf,g_dwOpcodeSize,addr @dwBytesWrited
;创建线程
invoke CreateRemoteThread,@hProc,NULL,0,@lpAddr,NULL,0,NULL
ret
Inject endp
解析汇编为机器码
Assembly proc USES edi ecx dwCip:DWORD,hDlg:HWND
LOCAL @dwLineCount:DWORD
LOCAL @hEdt:HWND
LOCAL @xed:XEDPARSE
invoke GetDlgItem,hDlg,EDT_ASM
mov @hEdt,eax
;获得编辑框输入的行数
invoke SendMessage,@hEdt,EM_GETLINECOUNT,0,0
mov @dwLineCount,eax
xor ebx,ebx
mov g_dwOpcodeSize,0
;遍历每行
.while ebx < @dwLineCount
invoke RtlZeroMemory,addr @xed,type @xed
;获取一行汇编文本
lea eax,@xed.instr_
mov word ptr [eax],XEDPARSE_MAXBUFSIZE
invoke SendMessage,@hEdt,EM_GETLINE,ebx,eax
;汇编
;这里dwCip是另一个程序的内存地址
mov ecx,dwCip
;g_dwOpcodeSize表示自增指令大小
add ecx,g_dwOpcodeSize
lea eax,@xed.cip
mov dword ptr [eax],ecx
invoke XEDParseAssemble,addr @xed
.if eax==XEDPARSE_ERROR
invoke MessageBox,NULL,NULL,offset g_szErr,MB_OK
mov eax,FALSE
ret
.endif
;拷贝机器码
mov edi,offset g_aryOpcodeBuf
add edi,g_dwOpcodeSize
invoke crt_memcpy,edi,addr @xed.dest,@xed.dest_size
;更新汇编后机器码长度
mov eax,@xed.dest_size
add g_dwOpcodeSize,eax
inc ebx
.endw
mov eax,TRUE
ret
Assembly endp
完成代码
;InjectCode.asm
.386
.model flat, stdcall ;32 bit memory model
option casemap :none ;case sensitive
include InjectCode.inc
include windows.inc
include msvcrt.inc
includelib msvcrt.lib
include kernel32.inc
include user32.inc
.data
g_szCol0Title db "PID",0
g_szCol1Title db "进程名称",0
g_szFmt db "%d",0
g_aryOpcodeBuf db 1000h dup(0)
g_dwOpcodeSize dd 0
g_szErr db "汇编语法错误",0
.code
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke InitCommonControls
invoke DialogBoxParam,hInstance,IDD_DIALOG1,NULL,addr DlgProc,NULL
invoke ExitProcess,0
;########################################################################
Assembly proc USES edi ecx dwCip:DWORD,hDlg:HWND
LOCAL @dwLineCount:DWORD
LOCAL @hEdt:HWND
LOCAL @xed:XEDPARSE
invoke GetDlgItem,hDlg,EDT_ASM
mov @hEdt,eax
;获得编辑框输入的行数
invoke SendMessage,@hEdt,EM_GETLINECOUNT,0,0
mov @dwLineCount,eax
xor ebx,ebx
mov g_dwOpcodeSize,0
;遍历每行
.while ebx < @dwLineCount
invoke RtlZeroMemory,addr @xed,type @xed
;获取一行汇编文本
lea eax,@xed.instr_
mov word ptr [eax],XEDPARSE_MAXBUFSIZE
invoke SendMessage,@hEdt,EM_GETLINE,ebx,eax
;汇编
mov ecx,dwCip
add ecx,g_dwOpcodeSize
lea eax,@xed.cip
mov dword ptr [eax],ecx
invoke XEDParseAssemble,addr @xed
.if eax==XEDPARSE_ERROR
invoke MessageBox,NULL,NULL,offset g_szErr,MB_OK
mov eax,FALSE
ret
.endif
;拷贝机器码
mov edi,offset g_aryOpcodeBuf
add edi,g_dwOpcodeSize
invoke crt_memcpy,edi,addr @xed.dest,@xed.dest_size
;更新汇编后机器码长度
mov eax,@xed.dest_size
add g_dwOpcodeSize,eax
inc ebx
.endw
mov eax,TRUE
ret
Assembly endp
Inject proc dwPid:DWORD,hDlg:HWND
LOCAL @hProc:HWND
LOCAL @lpAddr:LPVOID
LOCAL @dwBytesWrited:DWORD
;得到进程句柄并获取所有权限
invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,dwPid
;保存进程句柄
mov @hProc,eax
;申请内存
invoke VirtualAllocEx,@hProc,NULL,1000h,MEM_COMMIT,PAGE_EXECUTE_READWRITE
;保存内存引用
mov @lpAddr,eax
invoke Assembly,@lpAddr,hDlg
.if eax==FALSE
ret
.endif
;内存写入
invoke WriteProcessMemory,@hProc,@lpAddr,offset g_aryOpcodeBuf,g_dwOpcodeSize,addr @dwBytesWrited
;创建线程
invoke CreateRemoteThread,@hProc,NULL,0,@lpAddr,NULL,0,NULL
ret
Inject endp
Refresh proc hLstv:HWND
LOCAL @hSnap:HANDLE
LOCAL @pe32:PROCESSENTRY32
LOCAL @szBuff[32]:BYTE
invoke SendMessage,hLstv,LVM_DELETEALLITEMS ,0, 0
invoke RtlZeroMemory,addr @pe32,type @pe32
mov @pe32.dwSize,type @pe32
;捕获进程快照
invoke CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS,0
mov @hSnap,eax
;遍历快照的程序
invoke Process32First , @hSnap,addr @pe32
.if eax !=0
.repeat
invoke wsprintf,addr @szBuff,offset g_szFmt,@pe32.th32ProcessID
;插入行
invoke InsertItem,hLstv,addr @szBuff,@pe32.th32ProcessID
;设置文本
invoke SetIemText,hLstv,0,1,addr @pe32.szExeFile
invoke Process32Next,@hSnap,addr @pe32
.until eax==0
.endif
ret
Refresh endp
OnInitDlg proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL @hLstv:HWND
;得到窗口句柄对应的控件
invoke GetDlgItem,hWin,LV_PROCESS
mov @hLstv,eax
;列表控件,设置列
invoke InsertColum,@hLstv,0,offset g_szCol0Title,60
;
invoke InsertColum,@hLstv,1,offset g_szCol1Title,60
;网格线和选中
;发送信息插入列
invoke SendMessage,@hLstv,LVM_GETEXTENDEDLISTVIEWSTYLE,0, 0
or eax,LVS_EX_FULLROWSELECT or LVS_EX_GRIDLINES
invoke SendMessage,@hLstv,LVM_SETEXTENDEDLISTVIEWSTYLE,0, eax
invoke Refresh, @hLstv
mov eax,TRUE
ret
OnInitDlg endp
DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL @hLstv:HWND
LOCAL @li:LVITEM
LOCAL @dwItem:DWORD
mov eax,uMsg
.if eax==WM_INITDIALOG
invoke OnInitDlg,hWin,uMsg,wParam,lParam
.elseif eax==WM_COMMAND
mov ebx,wParam
invoke GetDlgItem,hWin,LV_PROCESS
mov @hLstv,eax
.if bx == BTN_REFRESH
;得到窗口句柄对应的控件
invoke Refresh,@hLstv
.elseif bx ==BTN_INJECT
;执行注入
invoke SendMessage,@hLstv,LVM_GETSELECTIONMARK,0,0
mov @dwItem,eax
.if eax !=-1
invoke RtlZeroMemory,addr @li,type @li
mov @li.imask,LVIF_PARAM
push @dwItem
pop @li.iItem
invoke SendMessage, @hLstv,LVM_GETITEM,0,addr @li
mov eax,@li.lParam
invoke Inject,@li.lParam,hWin
.endif
.endif
.elseif eax==WM_CLOSE
invoke EndDialog,hWin,0
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
DlgProc endp
end start
;ListView.asm
.386
.model flat, stdcall ;32 bit memory model
option casemap :none ;case sensitive
include windows.inc
include msvcrt.inc
includelib msvcrt.lib
include user32.inc
.code
InsertColum proc hWnd:HWND,dwCol:DWORD,szTitle:LPSTR,dwWith:DWORD
LOCAL @lvc:LVCOLUMN
;内存置为0
invoke crt_memset,addr @lvc,0,type @lvc
mov @lvc.imask,LVCF_FMT or LVCF_TEXT or LVCF_WIDTH
;左对齐
mov @lvc.fmt,LVCFMT_LEFT
;指定宽度
push dwWith
pop @lvc.lx
;标题
push szTitle
pop @lvc.pszText
;发送信息插入列
invoke SendMessage,hWnd,LVM_INSERTCOLUMN,dwCol, addr @lvc
ret
InsertColum endp
InsertItem proc hWnd:HWND,szTitle:LPSTR,dwUserData:DWORD
LOCAL @li:LVITEM
invoke crt_memset,addr @li,0,type @li
mov @li.imask, LVIF_TEXT OR LVIF_PARAM
push szTitle
pop @li.pszText
push dwUserData
pop @li.lParam
;插入一个条目
invoke SendMessage,hWnd,LVM_INSERTITEM,0,addr @li
ret
InsertItem endp
SetIemText proc hWnd:HWND,dwRow:DWORD,dwCol:DWORD,szTitle:LPSTR
LOCAL @li:LVITEM
invoke crt_memset,addr @li,0,type @li
mov @li.imask, LVIF_TEXT
;指定行
push dwRow
pop @li.iItem
;指定列
push dwCol
pop @li.iSubItem
push szTitle
pop @li.pszText
invoke SendMessage,hWnd,LVM_SETITEMTEXT,0,addr @li
ret
SetIemText endp
end
解决Process32Next找不到的问题
Process32NextW
函数位于kernel32.inc
和kernel32.dll
中,但是在Masm32 r11中却没有这Process32NextA版本,因此你需要自行修正
修正方式:
修改kernel32.inc
声明
源文件
Process32FirstW PROTO STDCALL :DWORD,:DWORD
Process32NextW PROTO STDCALL :DWORD,:DWORD
修改后
Process32First PROTO STDCALL :DWORD,:DWORD
Process32Next PROTO STDCALL :DWORD,:DWORD
替换原始kernel32.dll
为windows sdk
中的
Topic: Process32First & Process32Next problem. (Read 21098 times)
以上是关于x86汇编实现一个注入器的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 创建反汇编解析器实例对象 | 设置汇编解析器显示细节 )(代码片段