import process; namespace process { class apiHook { ctor ( ... ) { { var prcs,err = ..process(...); if(!prcs) return null,err; this.process = prcs; this.loadLibrary = prcs.remoteApi("addr(ustring libName)","kernel32.dll","LoadLibraryW","stdcall") this.freeLibrary = prcs.remoteApi("bool(addr hModule)","kernel32.dll","FreeLibrary","stdcall") this.getProcAddress = prcs.remoteApi("addr(addr hModule,string lpProcName)","kernel32.dll","GetProcAddress","stdcall") this._hookfunc = {}; ..table.gc(this,"unInstallAll") } }; install = function( dllName, apiName, jmpDllName, jmpApiName ) { var hookInfo = {}; var addrTargetFunction = dllName if( type(dllName) == type.string ){ dllName = ..io.localpath(dllName) : dllName; var hModule = this.loadLibrary(dllName); if(!hModule) return null,"LoadLibrary('" + dllName + "') faild!"; addrTargetFunction = this.getProcAddress(hModule,apiName); if(!addrTargetFunction) return null,"GetProcAddress('" + apiName + "') faild!"; hookInfo.hModule = hModule; } else { jmpDllName = apiName; jmpApiName = jmpDllName; } var addrHookFunction = jmpDllName; if( type(jmpDllName) == type.string ){ jmpDllName = ..io.localpath(jmpDllName) : jmpDllName; var hModule = this.loadLibrary(jmpDllName); if(!hModule) return null,"LoadLibrary('" + jmpDllName + "') faild!"; addrHookFunction = this.getProcAddress(hModule,jmpApiName); if(!addrHookFunction) return null,"GetProcAddress('" + jmpApiName + "') faild!"; hookInfo.hHookModule = hModule; } var jmpOpCodeLen = 5; var addrProtect = this.process.protect(addrTargetFunction,0x40/*_PAGE_EXECUTE_READWRITE*/,jmpOpCodeLen * 2) if (!addrProtect) { error("修改内存属性失败!", 2); } var restoreOpCode = this.process.readString(addrTargetFunction,jmpOpCodeLen * 2 ); hookInfo.restoreOpCodeSize,restoreOpCode = getHookSize( restoreOpCode,jmpOpCodeLen ); var addrTrampoline = this.process.malloc( hookInfo.restoreOpCodeSize + jmpOpCodeLen,0x40/*_PAGE_EXECUTE_READWRITE*/) this.process.write( addrTrampoline,restoreOpCode, '\xE9'/*JMP*/, { int jmpAddr = addrTargetFunction + hookInfo.restoreOpCodeSize - (addrTrampoline + hookInfo.restoreOpCodeSize + jmpOpCodeLen ); } ) this.process.write( addrTargetFunction, '\xE9'/*JMP*/, { int jmpAddr = addrHookFunction - (addrTargetFunction + jmpOpCodeLen); } ) ..table.assign( hookInfo, { addrProtect = addrProtect; addrTrampoline = addrTrampoline; addrHookFunction = addrHookFunction; addrTargetFunction =addrTargetFunction; } ) this._hookfunc[addrTargetFunction] = hookInfo; return hookInfo; }; unInstall = function ( hookInfo ) { if (!hookInfo.addrTargetFunction) { return; } if(this.process.stillActive()){ this.process.suspend(); var restoreCode = this.process.readString(hookInfo.addrTrampoline ,hookInfo.restoreOpCodeSize) this.process.writeString(hookInfo.addrTargetFunction,restoreCode); this.process.protect( hookInfo.addrTargetFunction, hookInfo.addrProtect, hookInfo.restoreOpCodeSize ); this.process.mfree(hookInfo.addrTrampoline); if(hookInfo.hModule)this.freeLibrary(hookInfo.hModule); if(hookInfo.hHookModule)this.freeLibrary(hookInfo.hHookModule); this.process.resume(); } this._hookfunc[hookInfo.addrTargetFunction] = null; }; unInstallAll = function(){ for(k,hookInfo in this._hookfunc){ this.unInstall(hookInfo); } }; resume = function(){ return this.process.resume(); } } namespace apiHook { import ..raw.asm.opCode; getHookSize = ..raw.asm.opCode.getHookSize; } } /**intellisense() process.apiHook = 在外部32位进程内安装 API 函数钩子,\n作用仅仅是安装,需要要用 C,或 C++ 写 32位 dll 钩子。\n可以在 aardio 中通过远程 API 调用钩子 DLL 中的函数。\n具体用法可参考 process.ruffle 扩展库源码。\n\n进程内钩子请改用 thread.apiHook,\n线程内钩子请改用 raw.apiHook process.apiHook( = 创建 API Hook 工具 process.apiHook(.(进程ID) = 使用进程 ID 打开进程,并返回 API Hook 安装工具。\n失败则返回 null,以及错误信息. process.apiHook(.(执行文件,命令行参数,启动参数) = 运行执行文件或关联文档,并返回 API Hook 安装工具。\n也可以仅指定第二个参数运行纯命令行\n启动参数为 process.STARTUPINFO 结构体,可选,\n可以使用普通table对象替代启动参数.将自动转换为STARTUPINFO结构体 process.apiHook(.(执行文件,命令行参数,{suspended=true}) = 运行执行文件或关联文档,并返回 API Hook 安装工具。\n启动后暂停进程,可在安装钩子以后调用 resume() 函数继续运行进程 process.apiHook() = !process_apihook. !process_apihook.resume() = 继续运行进程 !process_apihook.install(.("拦截DLL模块名","拦截API函数名","钩子模块名","钩子API函数名") = 安装钩子,返回HookInfo对象\n也可以直接写拦截函数地址或钩子函数地址,\n但函数地址必须是目标进程内的函数地址,不可使用aardio函数,\n\n注意是在目标进程内调用LoadLibrary搜索DLL,\n默认搜索路径包含目标EXE所在目录,而非当前EXE所在目录\n但以斜杠开头的路径aardio会在当前进程中解析为完整路径 !process_apihook.process = 进程对象,\n!process. !process_apihook.loadLibrary(.("DLL模块名") = 在目标进程中加载DLL,返回数值类型句柄 !process_apihook.freeLibrary(.(模块地址) = 卸载DLL !process_apihook.getProcAddress(.(模块地址,"API函数名") = 查找外部进程API函数,返回函数地址 !process_apihook.unInstall(.(HookInfo) = 卸载钩子,\n传入参数必须是 install函数的返回值\n\n要注意的问题:\n1、如果钩子函数正在回调中卸载自身会导致目标进程崩溃,\n1、卸载钩子时目标函数不能正在使用中,\naardio会先暂停目标进程主线程,卸载完再恢复,\n但目标进程可能是多线程的,请避免目标函数正在被调用时去释放 !process_apihook.install() = !procss_hookInfo. !process_apihook.unInstallAll() = 释放所有钩子,\n该函数会在对象回收时自动调用\n如果不希望在进程关闭时卸载钩子,请将此函数赋值为null !procss_hookInfo.addrProtect = 函数内存保护属性 !procss_hookInfo.addrTrampoline = 用于调用原函数的跳板地址 !procss_hookInfo.addrHookFunction = 钩子函数地址 !procss_hookInfo.addrTargetFunction = 被拦截函数地址 !procss_hookInfo.hModule = 被拦截模块地址 !procss_hookInfo.hHookModule = 钩子模块地址 !procss_hookInfo.restoreOpCodeSize = 安装钩子覆盖指令长度 end intellisense**/