本程序在WinXP/SP2、ra2之1.006英文版(有中国超牛机器人的那个)运行通过且稳定无误。
;------------------------------------------------------------------------
;文件一:Ra2MDF.Asm 启动游戏 和 DLL注入
;------------------------------------------------------------------------
.586
.model flat,
stdcall
option casemap :
none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
.code
;------------------------------------------------------------------------
;把本程序拷入游戏文件夹,运行本程序,游戏被启动,本程序在后台运行,无界面
;本程序运行后启动“ra2.exe”,再由“ra2.exe”启动游戏程序,之后“ra2.exe”
;无用了,停掉它以节约内存。
;------------------------------------------------------------------------
_StartGame
proc
LOCAL StartInfo:STARTUPINFO
LOCAL PI:PROCESS_INFORMATION
invoke RtlZeroMemory,
addr StartInfo,sizeof STARTUPINFO
mov StartInfo.cb,sizeof STARTUPINFO
mov ecx,GAME_NAME
xor edx,
edx
invoke CreateProcess,
edx,
ecx,
edx,
edx,
edx,
edx,
edx,
edx,
addr StartInfo,
addr PI
;启动游戏
invoke Sleep,15000
;等10秒,游戏程序应该启动了吧?
invoke TerminateProcess,PI.hProcess,0h
;没用了,停掉它
invoke CloseHandle,PI.hProcess
;释放内存
ret
GAME_NAME:
db "ra2.exe",0
_StartGame
endp
start:
;------------------------------------------------------------------------
;
;
;------------------------------------------------------------------------
Main
proc uses edi esi
LOCAL @dwProcessID,@lpLoadLibrary,@lpDllName,@szDllFullPath[MAX_PATH]
invoke _StartGame
;启动游戏
lea edi,@szDllFullPath
invoke GetCurrentDirectory,MAX_PATH,
edi
call @F
db '\Ra2MD.dll',0
@@:
push edi
call lstrcat
;获取dll的全路径文件名
call @F
db 'Kernel32.dll',0
@@:
call GetModuleHandle
call @F
db 'LoadLibraryA',0
@@:
push eax
call GetProcAddress
;获取LoadLibrary函数地址
mov @lpLoadLibrary,
eax
invoke GetForegroundWindow
;取得游戏窗口的句柄
lea esi,@dwProcessID
invoke GetWindowThreadProcessId,
eax,
esi ;获取进程ID
invoke OpenProcess,PROCESS_CREATE_THREAD
or PROCESS_VM_OPERATION
or \
PROCESS_VM_WRITE,
FALSE,@dwProcessID
;打开进程
.if eax
mov esi,
eax
;********************************************************************
; 在进程中分配空间并将DLL文件名拷贝过去,然后创建一个LoadLibrary线程
;********************************************************************
invoke VirtualAllocEx,
eax,NULL,MAX_PATH,MEM_COMMIT,PAGE_READWRITE
;
.if eax
mov @lpDllName,
eax
invoke WriteProcessMemory,
esi,
eax,
edi,MAX_PATH,NULL
invoke CreateRemoteThread,
esi,NULL,0h,@lpLoadLibrary,@lpDllName,0h,NULL
;完成DLL注入
invoke CloseHandle,
eax
.endif
invoke CloseHandle,
esi
.endif
invoke ExitProcess,NULL
Main
endp
end start
;-------------------------------------------------------------------------------------
;文件二:Ra2DLL.Asm 用来被嵌入到其它进程执行的dll,完成热键、搜索、修改等全部功能
;作为游戏进程的一部分,可以直接访问游戏内存,不用ReadProcessMemory和WriteProcessMemory
;这样搜索速度相对要快一些。本例中所说的游戏版本与前面的相同。
;-------------------------------------------------------------------------------------
.586
.model flat,
stdcall
option casemap :
none
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
ADD_DATA1
equ 008373cch
;00883c84h ;其他版本要改这个地址值
;ADD_DATA2 equ 008373d0h ;00883c88h ;这个不用
ADD_DATA3_START
equ 01000000h
;搜索范围开始地址,可根据需要改动,但要跳过前两个地址
ADD_DATA3_END
equ 0f600000h
;搜索范围结束地址,可根据需要改动
MEMSIZE
equ 10000h
;每次读取数据块的大小,不宜太小
.code
_GetDataAddr
proc uses esi edi num,hmem
LOCAL N,ListMemSize,pListMem,ReadSize
LOCAL mbi:MEMORY_BASIC_INFORMATION
invoke GlobalLock,hmem
;锁定保存搜索结果的内存
mov pListMem,
eax
invoke GlobalSize,hmem
;保存搜索结果的内存大小
mov ListMemSize,
eax
mov edi,ADD_DATA1
;保存金钱数,以便后面比较搜索,原理见前文
mov edi,[
edi]
mov ecx,ADD_DATA3_START
;设置要搜索的内存地址范围开始处
.repeat ;循环搜索游戏内存
@@:
invoke VirtualQuery,
ecx,
addr mbi,sizeof MEMORY_BASIC_INFORMATION
;返回页面虚拟信息
.if mbi.State == MEM_COMMIT && mbi.Protect == PAGE_READWRITE
;已提交且为可读写的区域,加速搜索
invoke IsBadWritePtr,mbi.BaseAddress,mbi.RegionSize
.if !
eax
mov esi,mbi.BaseAddress
xor ecx,
ecx
.repeat
.if edi==[
esi+
ecx]
;数值相等,找到了?
mov eax,num
;地址num中记录了搜索结果的个数
inc dword ptr[
eax]
;搜索的结果个数加一
mov eax,
dword ptr[
eax]
shl eax,2h
;保存结果所需的内存大小
.if eax>ListMemSize
;如果搜索到的结果较多,内存用完,要重新分配内存
push eax
push ecx
add eax,1000h
;追加4K内存
invoke GlobalReAlloc,hmem,
eax,GMEM_MOVEABLE
;重新分配内存,原来的数据被复制过来
invoke GlobalLock,
eax
mov pListMem,
eax ;保存搜索结果的内存首地址
invoke GlobalSize,hmem
mov ListMemSize,
eax ;保存搜索结果的内存大小
pop ecx
pop eax
.endif
add eax,pListMem
;相当于pListMem[num]
mov edx,
esi
add edx,
ecx ;首地址+偏移地址=实际地址
mov [
eax-4h],
edx ;搜索的结果保存起来,pListMem[num-1]=实际地址
.endif
add ecx,4h
;金钱数为DWORD型数值,考虑到内存对齐,这里是不用担心漏掉的
.until ecx>=mbi.RegionSize
.endif
.endif
mov ecx,mbi.BaseAddress
add ecx,mbi.RegionSize
;下一区段首地址
.until ecx>=ADD_DATA3_END
;下一区段在搜索范围之外了吗?是则完成第一遍搜索
ret
_GetDataAddr
endp
;------------------------------------------------------------------------
;第二、三……遍的搜索,在第一次的结果中找,速度极快
;第二次按下“*”键便来到这里,一般只要两遍就可锁定。算法:有用地址向前移
;结果个数由num返回,如果num==1就算找到正确的金钱地址了
;------------------------------------------------------------------------
_FindAddrInList
proc uses edi esi num,hmem
LOCAL N
invoke GlobalLock,hmem
mov edi,
eax ;前次搜索结果保存的内存首地址
xor esi,
esi ;指针,指向第一个结果
mov N,
esi ;本次搜索到的个数初始化为0
.repeat ;逐个比较
mov edx,[
edi+
esi*4h]
;相当于edx=hmem[esi]
mov eax,ADD_DATA1
mov eax,[
eax]
.if eax==[
edx]
;等于金钱数吗?等则记录下来
push [
edi+
esi*4h]
mov eax,N
pop [
edi+
eax*4h]
;相当于hmem[N]=hmem[esi],即把搜索到的结果向hmem内存前面移
inc N
;搜索到的个数加一
.endif
mov eax,num
inc esi ;指针指向下一个结果
.until esi>=[
eax]
;每个都比较过了吗?是则完成这次搜索
mov edx,N
;这次搜索到的结果个数
mov [
eax],
edx ;修改原来的个数
shl edx,2h
;个数×4=内存大小
invoke GlobalReAlloc,hmem,
edx,GMEM_MOVEABLE
;释放多余的内存
ret
_FindAddrInList
endp
;------------------------------------------------------------------------
;找到了正确的地址,可以锁定金钱数值了:),每五秒锁定一次,按“-”键停锁
;游戏中钱数看起来有增有减,象未锁定一样,别人不容易发现你作弊
;------------------------------------------------------------------------
_WriteProcessData
proc uses edi esi hmem
mov esi,5h
;要锁定的金钱数,别太多,多了是会招贼来偷的:)
invoke GlobalLock,hmem
mov edi,[
eax]
;游戏中真正的保存金钱数的地址
.repeat
.if esi>=5h
;每五循环锁定一次
xor esi,
esi ;循环次数清0
mov dword ptr[
edi],2000
.endif
invoke Sleep,1000
;定时一秒
inc esi ;循环次数加一
invoke GetAsyncKeyState,VK_SUBTRACT
;按了“-”键吗?
.until eax;如果按了“-”键则结束循环
ret
_WriteProcessData
endp
;------------------------------
;新线程,检查按键,响应用户请求
;------------------------------
ThreadProc
Proc pParam:LPVOID
Local @dwNum,@hMem
invoke GlobalAlloc,GMEM_MOVEABLE,1000h
;预留内存空间,搜索时用来保存结果
mov @hMem,
eax ;搜索结果个数的不确定性需要我们用GlobalReAlloc来重新分配内存大小
mov @dwNum,0h
;搜索结果个数初始化为0
.while TRUE
invoke GetAsyncKeyState,VK_SUBTRACT
;按了“-”键吗?
.if eax
mov @dwNum,0h
;搜索结果个数置0,表示从未搜索过
invoke SetCursorPos,9h,9h
;把鼠标置于屏幕左上角,提醒游戏者,第一遍搜索时特别有用
.endif
invoke GetAsyncKeyState,VK_MULTIPLY
;按了“*”键吗?
.if eax ;按了热键“*”
.if @dwNum==0h
;搜索结果个数为0则从未搜索过,进行第一遍搜索
invoke _GetDataAddr,
addr @dwNum,@hMem
.elseif @dwNum>1h
;搜索结果个数非0则至少已搜过一遍且未找到正确地址
invoke _FindAddrInList,
addr @dwNum,@hMem
;再搜它一遍或几遍
.endif
.if @dwNum==1h
;搜索结果为1,说明找到正确地址了
invoke _WriteProcessData,@hMem
;去锁定它!
.endif
invoke MessageBeep,MB_OK
;发声提示游戏者,按键收到,该做的本程序都做过了
invoke SetCursorPos,9h,9h
;把鼠标置于屏幕左上角,提醒游戏者,第一遍搜索时特别有用
.endif
invoke Sleep,1000
.endw
invoke GlobalUnlock,@hMem
invoke GlobalFree,@hMem
ret
ThreadProc
endP
DllEntry
Proc _hInstance,_dwReason,_dwReserved
LOCAL @dwThreadID
.if _dwReason == DLL_PROCESS_ATTACH
invoke CreateThread,NULL,0h,
offset ThreadProc,NULL,NULL,
addr @dwThreadID
;创建一个新线程
invoke CloseHandle,
eax
.endif
mov eax,
TRUE
ret
DllEntry
Endp
End DllEntry
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。