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逻辑

这里我们单独使用一个汇编文件实现插入itemlistview中,由于比较简单所以不做过多解释,都是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.inckernel32.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.dllwindows sdk中的

Topic: Process32First & Process32Next problem. (Read 21098 times)

以上是关于x86汇编实现一个注入器的主要内容,如果未能解决你的问题,请参考以下文章

汇编器的NASM

使用来自 x64 注入器的 x86 dll 注入 x86 目标

x86 汇编器:浮点比较

x86 内联汇编器标志

GNU 汇编器 x86 指令后缀(如“mov.s”中的“.s”)如何工作?

x86汇编编程中如何表示FFFFFFBB等十六进制值?