的回调。跟进KiUserExceptionDispatcher函数发现,SEHandler必须在某个Image的领空
内才可以,直接 VirtualAllocEx 出的 RWE Page 是不行的。那么我们就在 kernel32.dll
的.text 块尾部放一个跳转,跳到我们的 SEHandler。完成后发现系统还是不调用我的
SEHandler……上网一搜,原来是个叫 SafeSEH 的东西在搞鬼。简单的说,SafeSEH 就是在
编译的时候计算出所有可能的 SEHandler 地址,保存在一个表中,如果发生异常时注册的
SEHandler 不在这个表中,就拒绝执行。这个表在 PE Image 的
OptionalHeader.DataDirectory[LOAD_CONFIG]指出。简单的将这个域清零是不行的,因为
系统在装载PE Image的时候会把这个表的地址复制一份保存起来,但是表本身还是引用PE
Image中的表,所以我们替换其中的一个就可以了,经过测试没有什么问题,这倒是有点意
外(毕竟不知道哪个地方的功能废掉了)。
怎样启动外挂倒是没什么新意,就是一个CreateRemoteThread,很招摇了。作者还试
过 QueueUserAPC 函数,只是魔兽的主线程从来就没进入过 Alertable 状态,我们的 APC
routine 得不到机会执行; SetThreadContext的方法感觉跟远程线程一样招摇,还不好操作;
Windows Hook的话,就需要一个DLL,所以也就这个样了。
代码编写
程序采用 32 位 ASM 编写,汇编器是 MASM6(高版本的不好用),以下代码在 Windows 7
(6.1.7600),魔兽争霸1.24e上测试成功。另外推荐一下MASMPlus,简单好用。
.686
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
include kernel32.inc
includelib user32.lib;实际上这两句只是为了哄MASM开心
includelib kernel32.lib
PingMiniMapEx proto x:DWORD, y:DWORD, duration:DWORD, color:DWORD,
extraEffects:DWORD
DisplayText proto pString:DWORD, dwDuration:DWORD
MainProc proto u1:DWORD, u2:DWORD, idEvent:DWORD, u4:DWORD
GameOriginalBase equ 6F000000h ;魔兽争霸的Game.dll的 ImageBase
OFFS macro p, s:=<START> ;计算偏移值,自定位代码使用的,OFFSet
exitm <(offset p - offset s)>
endm
RLC macro p, basereg:=<ebx> ;重定位变量,ReLoCation
exitm <[basereg+OFFS(p)]>
endm
push_offset_RLC macro p, basereg:=<ebx> ; = push offset RLC(xxx)
push OFFS(p)
add DWORD ptr [esp], basereg
endm
GetBase macro reg:=<ebx> ;取得当前代码块的基址,重定位用的
local l
call l
l:
pop reg
sub reg, OFFS(l)
endm
T macro t ;方便的定义字符串的宏,直接嵌在代码中了
local l, l1
jmp l1
l:
db t, 0
l1:
exitm <l>
endm
RLCInvoke MACRO FunArgs:VARARG
;这个宏是抄的 MASMPlus 里面的@fcall 宏,模仿 invoke 用的,稍微修改一下可以用在
重定位的情况下了,因为太长所以省略了。
ENDM
GetGameAddr macro _addr, reg:=<eax>, basereg:=<ebx> ;取得重定位后的 Game.dll
地址
mov reg, RLC(hGameDll, basereg)
add reg, (_addr - GameOriginalBase)
endm
GameCall macro _addr, reg:=<eax>, basereg:=<ebx> ;调用Game.dll中的函数
GetGameAddr _addr, reg, basereg
call reg
endm
;以下的常数都是上文分析出的函数地址,P代表私有函数,JN代表Jass native
PSaveString equ 6F3BB560h ; Private, fastcall, char * -> stringid
PAddNative equ 6F455C20h ; Private, fastcall, funcaddr, funcname, funcsig
-> void
PSIdToPointer equ 6F45A150h ; Private, thiscall, jassenv, stringid -> ptr
to a struct
PGetCurrentJassEnv equ 6F44BDF0h ; Private, fastcall, id = 1 => main jass,
id = 2 => ai jass (guessed)
PInitNatives equ 6F3D4B60h ; Private, used for hooking
;constant native GetLocalPlayer takes nothing returns player
JNGetLocalPlayer equ 6F3BC6A0h
;native DisplayTimedTextToPlayer takes player toPlayer, real x, real y, real
duration, string message returns nothing
JNDisplayTimedTextToPlayer equ 6F3CC4F0h
;native PingMinimapEx takes real x, real y, real duration, integer red,
integer green, integer blue, boolean extraEffects returns nothing
JNPingMinimapEx equ 6F3B91A0h
;constant native GetUnitX takes unit whichUnit returns real
JNGetUnitX equ 6F3C6050h |