win32 masm32 汇编学习 及 远程线程实例

"门“ 指向某个优先级高的程序所规定的入口点,所有优先级低的程序调用优先级高的程序只能通过门重定向
门:中断门,自陷门,任务门。


masm32.zip
copy D:\Program Files\Microsoft Visual Studio\VC98\Bin\nmake.exe to  ***\masm32\bin


相应cmd设置临时环境变量
@echo off
set include=f:\masm32\Include;D:\Program Files\Microsoft Visual Studio\VC98\Include;D:\Program Files\Microsoft Visual Studio\VC98\MFC\Include
set lib=f:\masm32\lib
set path=f:\masm32\bin;%path%
@echo on


\**\nmake


.model flat   MASM自动为各段寄存器做了如下定义:
ASSUME cs:FLAT,ds:FLAT,ss:flat,es:flat,fs:error,gs:error


全部段源程序结构:
.386
.model flat,stdcall
option casemap:none
< Include 文件定义>
.stack [堆栈段大小]
.data
<一些初始化过的变量定义>
.data? ;不会占用EXE文件空间
<一些没初始化过的变量定义>
.const
<一些常量定义>
.code
<代码>
<开始标号>
<其他语句>
end 开始标号


invoke 不是80x86的伪指令,它只是MASM编译器的伪指令,实现push参数和call函数名而已。
对汇编而言,所有参数和返回值 只有一个dword类型,所以要么是简单类型,要么是指针。
返回值放在eax中


函数名 proto [距离] [语言] [参数1]:数据类型,[参数2]:数据类型,....
proto:函数声明伪指令
距离:NEAR,FAR...(WIN32只有只有一个平坦的段,无所谓距离,所以忽略)
语言:.model定义的默认值
对于WIN32它只关注参数个数,参数名为是提高可读性
MessageBox Proto hWnd:dword,lpText:dword,lpCaption:dword,uType:dword
MessageBox Proto  :dword,:dword,:dword,:dword  
其实这两定义是一样的


只有windows NT才完全支持Unicode,
if UNICODE
MessageBox equ <MessageBoxW>
else
MessageBox equ <MessageBoxA>
endif


//@@做标号
@F本指令后第一个@@标号,@B本指令前的第一个@@标号


如果要定义两个字符串"hello,world!",和"hello agin",则每个字符串后跟回车和换行符,最后以一个0字符结尾,
szText db 'hello,world!',0dh,0ah,'hello agin',0dh,0ah,0


.data? 后面的默认是0,不是随机的  //与这全局变量不同,local后的局部变量起始值是随机的


MASM用local伪指令来定义局部变量,local伪指令必须proc伪指令后,其他指令开始前。因为变量数量要早确定下来


结构构成员引用:
1: mov eax,strutname.lpfn
2: mov esi,offset strutname
mov eas,[esi+STRUTNAME.lpfn]
3: mov esi,offset strutname
assume esi:ptr STRUTNAME
mov eax,[esi].lpfn
...
assume esi:nothing




.data
bTest1 db 12h
wTest2 dw 1234h


mov ax,bTest1 ;ax = 3412h
movzx ax,bText1 ;ax = 0012h movsx:带符号扩展


sizeof/lengthof伪指令
如果hello world分两行定义:
szHello db 'hello',odh,oah
db 'world',0
sizeof szHello为7,原因masm中变量只认一行,db 'world',0 实际上是没有名称的数据定义。


获取变量地址:
全局变量:mov 寄存器,offset 变量名 ;编译时
局部变量:lea    寄存器,[ebp-4] ;运行时
参数局部变量:addr 参数变量
对局部变量取地址的时候,addr伪操作只能用在invoke的参数中,addr实际是先取地址到eax,再代替到参数里
invoke Test,eax,addr szHello ;错误
翻译如下:
lea eax,addr szHello
push eax
push eax ;已经被上面覆盖
call Test


invoke Test,addr szHello,eax ;正确


子程序的定义:
子程序名  proc [...][...][VARARG]
local 局部变量列表
指令
子程序名 endp
proc后的参数列表中参数不能和全局变量及子程序中局部变量重名,VARARG指些子程序是可变参数;proto为声明,如上


调用约定有:C, SysCall,StdCall,BASIC,FORTRAN,PASCAL具体找度娘


条件测试语句:==, != , >,>=,<,<=,&,!,&&,||
限制:左边只能是变量或者寄存器,不能是常量;
表达式两边不能同时为变量,但可以同时为寄存器。
分支语句:.if/.elseif/.else/.endif,如果不加点,则变成条件汇编伪操作


循环语句:
.while  条件测试表达式
指令
[.break [.if 退出条件]]
[.continue]
.endw
或者
.repeat
指令
[.break [.if 退出条件]]
[.continue]
.until 条件测试表达式 (或.untilcxz [条件测试表达式])
上面的相当while循环,下面的相当do...while循环
代码规范:
参数用_开头,局部变量用@开头,内部子程序用_开头
尽量不要用宏定义,以免影响可读性
子程序规模不要太大,注释写好,指针安全检查,做好子程序库以备未来编写大程序。


第四章:第一个窗口程序
模块句柄在数值上等于程序在内存中装入的起始地址,GetMododuleHandle,模 块句柄便于访问程度中的各种资源。
postmessage/sendmessage:
当消息中用到指针时,postmessage函数来发送的消息都不会成功。




10.1.4
windows的“堆”分为默认堆和私有堆两种。默认堆是在程序初始化时由OS自动创建的,所有的标准的内存管理函数都是在默认堆中申请内存的;而私有堆相当于是在默认堆中保留了一大块内存,
默认堆只有一个私有堆可以有多个,默认堆可以直接使用,而私有堆必须先创建。
如果多个模块在默认堆中使用内存会交叉排序,一个模块越界可以很难找到问题,如果多个模块在各自的私有堆,越界更容易定位。
私有堆创建函数heapcreate/heapdestory
私有堆中分配和释放内存块heapalloc/heaplock/....


在程序运行的时候,进程中每个地址都可以牌下列3种状态的1种中:
占用状态:线程地址已映射物理内存,也称已提交状态
自由状态:没有映射到物理内存,线程地址没有被使用 //进程刚开始的起始状态
保留状态:虽然没有映射到物理内存,但它不会被使用,直到希望使用他为止




当使用上面的标准内存管理函数时,用户无法指定内存位于哪个线程地址,使用virtual开头的虚拟内存管理函数可以做到这一点。如virtualalloc


VirtualAllocEx/CreateRemoteThread相比 Virtualalloc/createthread多了个hprocess,针对相应进程操作
virtualallocex需要对相应进程有process_vm_operation权限
 
远程线程存在:重定位和函数的导入问题
对高级语言不可能解决重定位问题,因为没办法在机器码级别上操作,c语言也没有办法,通过注入dll绕过去,因为装载DLL会自动重定位


dwVar dd
call @F
@@:
pop ebx
sub ebx,offset @B
mov eax,[ebx+offset dwVar]


:00401000 00000000 BYTE 4 DUP(0)
:00401004 EB00000000 call 00401009
:00401009 5B pop ebx
:0040100A 81EB09104000 sub ebx,00401009
:00401010 8B8300104000 mov eax, dword ptr [ebx+00401000]


当这段代码移动00401000的位置时如下:
:00801000 00000000 BYTE 4 DUP(0)
:00801004 EB00000000 call 00801009
:00801009 5B pop ebx //此时ebx为:00801009
:0080100A 81EB09104000 sub ebx,00401009
:00801010 8B8300104000 mov eax, dword ptr [ebx+00401000]


远程代码用的win32 api,api又存在于是dll中,同时dll装载基地不同,api函数地址也不同,所以手动完成:
1. loadlibary 使用的dll
2. getprocaddress api函数


其中1,2用到dll名字和api函数名都要采用上面重定位的方法保存好




远程线程创建步骤:
1.VirtualAllocEx申请目标进程的一块内存, 要有hProcess有 PROCESS_VM_OPERATION, 内存块应该有PAGE_EXECUTE_READWRITE属性
2.writeProcessMemory写入代码及数据
3.CreateRemoteThread   要hProcess有PROCESS_CREATE_THREAD权限
//remotethread code and data
; RemoteCode.asm
; 一段自定位的代码,可以用来创建一个窗口
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
REMOTE_CODE_START	equ this byte

_lpLoadLibrary		dd	?	;导入函数地址表
_lpGetProcAddress	dd	?
_lpGetModuleHandle	dd	?

_lpDestroyWindow	dd	?
_lpPostQuitMessage	dd	?
_lpDefWindowProc	dd	?
_lpLoadCursor		dd	?
_lpRegisterClassEx	dd	?
_lpCreateWindowEx	dd	?
_lpShowWindow		dd	?
_lpUpdateWindow		dd	?
_lpGetMessage		dd	?
_lpTranslateMessage	dd	?
_lpDispatchMessage	dd	?

_hInstance	dd	?
_hWinMain	dd	?
_szClassName	db	'RemoteClass',0
_szCaptionMain	db	'RemoteWindow',0
_szDllUser		db	'User32.dll',0
_szDestroyWindow	db	'DestroyWindow',0
_szPostQuitMessage	db	'PostQuitMessage',0
_szDefWindowProc	db	'DefWindowProcA',0
_szLoadCursor		db	'LoadCursorA',0
_szRegisterClassEx	db	'RegisterClassExA',0
_szCreateWindowEx	db	'CreateWindowExA',0
_szShowWindow		db	'ShowWindow',0
_szUpdateWindow		db	'UpdateWindow',0
_szGetMessage		db	'GetMessageA',0
_szTranslateMessage	db	'TranslateMessage',0
_szDispatchMessage	db	'DispatchMessageA',0,0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_RemoteThread	proc	uses ebx edi esi lParam
		local	@hModule

		call	@F
		@@:
		pop	ebx
		sub	ebx,offset @B
;********************************************************************
		_invoke	[ebx + _lpGetModuleHandle],NULL
		mov	[ebx + _hInstance],eax
		lea	eax,[ebx + offset _szDllUser]
		_invoke	[ebx + _lpGetModuleHandle],eax
		mov	@hModule,eax
		lea	esi,[ebx + offset _szDestroyWindow]
		lea	edi,[ebx + offset _lpDestroyWindow]
		.while	TRUE
			_invoke	[ebx + _lpGetProcAddress],@hModule,esi
			mov	[edi],eax
			add	edi,4
			@@:
			lodsb
			or	al,al
			jnz	@B
			.break	.if ! byte ptr [esi]
		.endw
;********************************************************************
		call	_WinMain
		ret

_RemoteThread	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMain	proc	uses ebx edi esi,hWnd,uMsg,wParam,lParam

		call	@F
		@@:
		pop	ebx
		sub	ebx,offset @B
;********************************************************************
		mov	eax,uMsg
		.if	eax ==	WM_CLOSE
			_invoke	[ebx + _lpDestroyWindow],hWnd
			_invoke	[ebx + _lpPostQuitMessage],NULL
;********************************************************************
		.else
			_invoke	[ebx + _lpDefWindowProc],hWnd,uMsg,wParam,lParam
			ret
		.endif
;********************************************************************
		xor	eax,eax
		ret

_ProcWinMain	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ZeroMemory	proc	_lpDest,_dwSize

		push	edi
		mov	edi,_lpDest
		mov	ecx,_dwSize
		xor	eax,eax
		cld
		rep	stosb
		pop	edi
		ret

_ZeroMemory	endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain	proc	uses ebx esi edi _lParam
		local	@stWndClass:WNDCLASSEX
		local	@stMsg:MSG

		call	@F
		@@:
		pop	ebx
		sub	ebx,offset @B
;********************************************************************
		invoke	_ZeroMemory,addr @stWndClass,sizeof @stWndClass
		_invoke	[ebx + _lpLoadCursor],0,IDC_ARROW
		mov	@stWndClass.hCursor,eax
		push	[ebx + _hInstance]
		pop	@stWndClass.hInstance
		mov	@stWndClass.cbSize,sizeof WNDCLASSEX
		mov	@stWndClass.style,CS_HREDRAW or CS_VREDRAW
		lea	eax,[ebx +  offset _ProcWinMain]
		mov	@stWndClass.lpfnWndProc,eax
		mov	@stWndClass.hbrBackground,COLOR_WINDOW + 1
		lea	eax,[ebx + offset _szClassName]
		mov	@stWndClass.lpszClassName,eax
		lea	eax,@stWndClass
		_invoke	[ebx + _lpRegisterClassEx],eax
;********************************************************************
; 建立并显示窗口
;********************************************************************
		lea	eax,[ebx + offset _szClassName]
		lea	ecx,[ebx + offset _szCaptionMain]
		_invoke	[ebx + _lpCreateWindowEx],WS_EX_CLIENTEDGE,eax,ecx,\
			WS_OVERLAPPEDWINDOW,\
			100,100,600,400,\
			NULL,NULL,[ebx + _hInstance],NULL
		mov	[ebx + _hWinMain],eax
		_invoke	[ebx + _lpShowWindow],[ebx + _hWinMain],SW_SHOWNORMAL
		_invoke	[ebx + _lpUpdateWindow],[ebx + _hWinMain]
;********************************************************************
; 消息循环
;********************************************************************
		.while	TRUE
			lea	eax,@stMsg
			_invoke	[ebx + _lpGetMessage],eax,NULL,0,0
			.break	.if eax	== 0
			lea	eax,@stMsg
			_invoke	[ebx + _lpTranslateMessage],eax
			lea	eax,@stMsg
			_invoke	[ebx + _lpDispatchMessage],eax
		.endw
		ret

_WinMain	endp
REMOTE_CODE_END		equ this byte
REMOTE_CODE_LENGTH	equ offset REMOTE_CODE_END - offset REMOTE_CODE_START
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//createremotethread code
; RemoteThread.asm
; 向 Explorer.exe 进程中嵌入一段远程执行的代码
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff RemoteThread.asm
; rc RemoteThread.rc
; Link /subsystem:windows RemoteThread.obj RemoteThread.res
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		.386
		.model flat, stdcall
		option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include		windows.inc
include		user32.inc
includelib	user32.lib
include		kernel32.inc
includelib	kernel32.lib
include		Macro.inc
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		.data?
lpLoadLibrary	dd	?
lpGetProcAddress dd	?
lpGetModuleHandle dd	?
dwProcessID	dd	?
dwThreadID	dd	?
hProcess	dd	?
lpRemoteCode	dd	?

		.const
szErrOpen	db	'无法打开远程线程!',0
szDesktopClass	db	'Progman',0
szDesktopWindow	db	'Program Manager',0
szDllKernel	db	'Kernel32.dll',0
szLoadLibrary	db	'LoadLibraryA',0
szGetProcAddress db	'GetProcAddress',0
szGetModuleHandle db	'GetModuleHandleA',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

include		RemoteCode.asm

start:
		invoke	GetModuleHandle,addr szDllKernel
		mov	ebx,eax
		invoke	GetProcAddress,ebx,offset szLoadLibrary
		mov	lpLoadLibrary,eax
		invoke	GetProcAddress,ebx,offset szGetProcAddress
		mov	lpGetProcAddress,eax
		invoke	GetProcAddress,ebx,offset szGetModuleHandle
		mov	lpGetModuleHandle,eax
;********************************************************************
; 查找文件管理器窗口并获取进程ID,然后打开进程
;********************************************************************
		invoke	FindWindow,addr szDesktopClass,addr szDesktopWindow
		invoke	GetWindowThreadProcessId,eax,offset dwProcessID
		mov	dwThreadID,eax
		invoke	OpenProcess,PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or \
			PROCESS_VM_WRITE,FALSE,dwProcessID
		.if	eax
			mov	hProcess,eax
;********************************************************************
; 在进程中分配空间并将执行代码拷贝过去,然后创建一个远程线程
;********************************************************************
			invoke	VirtualAllocEx,hProcess,NULL,REMOTE_CODE_LENGTH,MEM_COMMIT,PAGE_EXECUTE_READWRITE
			.if	eax
				mov	lpRemoteCode,eax
				invoke	WriteProcessMemory,hProcess,lpRemoteCode,\
					offset REMOTE_CODE_START,REMOTE_CODE_LENGTH,NULL
				invoke	WriteProcessMemory,hProcess,lpRemoteCode,\			;远程代码及数据放在当前进程的代码段,不能修改本地的代码段
					offset lpLoadLibrary,sizeof dword * 3,NULL						;应该去遍历目标进程这三个函数。
				mov	eax,lpRemoteCode
				add	eax,offset _RemoteThread - offset REMOTE_CODE_START
				invoke	CreateRemoteThread,hProcess,NULL,0,eax,0,0,NULL
				invoke	CloseHandle,eax
			.endif
			invoke	CloseHandle,hProcess
		.else
			invoke	MessageBox,NULL,addr szErrOpen,NULL,MB_OK or MB_ICONWARNING
		.endif
		invoke	ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		end	start


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值