push 1 ; enable ?
push 14h ; 14h = SE_DEBUG_PRIVILEGE
call eax
pop eax
RLCInvoke OpenThread, THREAD_ALL_ACCESS, FALSE, esi
mov esi, eax
RLCInvoke SuspendThread, esi
mov edi, hKernel32
mov eax, (IMAGE_DOS_HEADER ptr [edi]).e_lfanew
add edi, eax
;使 kernel32.dll的整个领空可读可写可执行
mov eax, (IMAGE_NT_HEADERS32 ptr [edi]).OptionalHeader.SizeOfImage
push 0
RLCInvoke VirtualProtect, hKernel32, eax, PAGE_EXECUTE_READWRITE, esp
pop eax
push edi
;寻找kernel32.dll的.text 块尾部的空隙,放置跳转指令
xor eax, eax
mov ax, (IMAGE_NT_HEADERS32 ptr [edi]).FileHeader.SizeOfOptionalHeader
lea edi, [edi+eax+(sizeof(DWORD)+sizeof(IMAGE_FILE_HEADER))]
mov edi, (IMAGE_SECTION_HEADER ptr
[edi+sizeof(IMAGE_SECTION_HEADER)]).VirtualAddress ; Start of 2nd section
(RVA)
add edi, hKernel32
sub edi, 40h
lea eax, RLC(BreakpointHandler)
lea edx, RLC(hookaddr)
mov DWORD ptr [edx], eax
dec edx
RLCInvoke RtlMoveMemory, edi, edx, 6
pop edx ; pair with 'push edi' above
;替换SafeSEH表中的值
mov eax, (IMAGE_NT_HEADERS32 ptr
[edx]).OptionalHeader.DataDirectory[SIZEOF(IMAGE_DATA_DIRECTORY)*IMAGE_DIRE
CTORY_ENTRY_LOAD_CONFIG].VirtualAddress
.if eax
add eax, hKernel32
.if DWORD ptr [eax] == 48h ; dwSize
mov eax, DWORD ptr [eax+40h] ; SafeSEH Table ptr, VA
mov ecx, edi
sub ecx, hKernel32
mov [eax+4], ecx ; 替换第一条不管用,作者也没有时间深究,就替换的第二条
.endif
.endif
push edi
lea edi, stContext
RLCInvoke RtlZeroMemory, edi, sizeof stContext
;取得魔兽主线程的CONTEXT
mov stContext.ContextFlags, CONTEXT_DEBUG_REGISTERS OR CONTEXT_FULL
RLCInvoke GetThreadContext, esi, edi
pop edi
;替换主线程SEH 链的最后一个为我们的异常处理函数
mov edx, stContext.regFs
RLCInvoke GetThreadSelectorEntry, esi, edx, addr stLdt
mov ah, stLdt.HighWord1.Bytes.BaseHi
mov al, stLdt.HighWord1.Bytes.BaseMid
shl eax, 16
mov ax, stLdt.BaseLow
.while DWORD ptr [eax] != -1
mov eax, [eax]
.endw
mov DWORD ptr [eax+4], edi
;设置DRx寄存器
GetGameAddr PInitNatives
mov stContext.iDr0, eax
GetGameAddr JNCreateUnit
mov stContext.iDr1, eax
mov stContext.iDr7,0101b ; DR0 DR1 valid, global, execute, 1 byte
mov stContext.ContextFlags, CONTEXT_DEBUG_REGISTERS
RLCInvoke SetThreadContext, esi, addr stContext
RLCInvoke ResumeThread, esi
RLCInvoke CloseHandle, esi
mov DWORD ptr RLC(dwStatus), 0
RLCInvoke ExitThread, 0
ret
FirstRun endp
;解析输入表的例程
resolve_imports:
push esi ; LoadLibrary
push edi ; GetProcAddress
mov esi, eax
push esi
call DWORD ptr [esp+8h] ; LoadLibrary
mov edi, eax
call next_str
.while DWORD ptr [esi]
push esi
push edi
call DWORD ptr [esp+8h] ; GetProcAddress
mov DWORD ptr [esi], eax
call next_str
.endw
pop edi
pop esi
ret
next_str:
.while BYTE ptr [esi]
inc esi
.endw
inc esi
ret
;用来提示地方英雄位置的TimerProc
MainProc proc uses ebx u1:DWORD, u2:DWORD, idEvent:DWORD, u4:DWORD
GetBase
mov ecx, 1
GameCall PGetCurrentJassEnv
;如果当前的 JassEnv 跟上一次的 JassEnv 不一样,那么就说明游戏已经结束,终
止 Timer
.if eax != DWORD ptr RLC(dwLastJassEnv)
RLCInvoke KillTimer, 0, RLC(hTimer)
mov DWORD ptr RLC(hTimer), 0
mov DWORD ptr RLC(dwStatus), 0
ret
.endif
call PingHeros
ret
MainProc endp
;用来在魔兽争霸中显示字符串的函数,通过调用DisplayTimedTextToPlayer实现。
CP_UTF8 equ 65001
DisplayText proc pString:DWORD, dwDuration:DWORD
LOCAL unicode [400h]:BYTE |