📄 c-apiworks.txt
字号:
ApiWorks is very complex Scout that allows loading given module(s) and establishing
"hooks".
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
ApiWorks functions have ANSI(A)/UNICODE(W) form. UNICODE strings are converted
to ANSI strings - some characters may have different meaning in calling process and
in Target.
Every string passed to ApiWorks functions can have (including zero terminator)
max. MAX_PATH characters. If it has more, ApiWorks returns ErrorAHException.
For successful ApiWorks execution, KERNEL32.dll mustn't have altered export entries
for GetModuleHandleA, LoadLibraryA, GetProcAddress, VirtualQuery, GetModuleFileNameA,
VirtualProtect, lstrcmpiA, LocalAlloc, LocalFreee, FlushInstructionCache, ordinal 1.
If they are altered, ApiWorks may fail with ErrorAHRemote.
9x: When a (large) module(s) is/are about to be loaded into more/all processes,
there must be "enough" (~100 MB) free space available on the drive with paging file
(Win386.swp).
NT: Don't forget to set appropriate access to module to Hooks_DLL. Typically set
Read & Execute for Everyone. It is important for intersession hooking. The same applies
onto imported modules (e.g. ApiHooks.dll, PrcWorks.dll, ..).
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
ApiWorks exports these functions for hooking:
DWORD __stdcall EstablishApiHooks(PRCINFO pRCI, LPCTSTR lpszDll, DWORD ProcessId, LONG dwMilliseconds);
DWORD __stdcall hEstablishApiHooks(PRCINFO pRCI, LPCTSTR lpszDll, HANDLE hProcess, LONG dwMilliseconds);
lpszDll is module that is loaded into Target and which exposes ApiHookChain.
If lpszDll is already present in Target
- and dwMilliseconds is even value, EAH returns with ErrorAWSuccess immediatelly
(hooks are taken as applied already).
- and dwMilliseconds is odd value lpszDll usage count is incremented (LoadLibrary)
and hooks are reapplied.
lpszDll is loaded, gets DLL_PROCESS_ATTACH followed by DLL_THREAD_DETACH notification
for the same thread.
lpszDll is also called Hooks_DLL in the following text.
dwMilliseconds is ExpTime user gives EAH function to establish API hooks.
if(dwMilliseconds & 1) { // dwMilliseconds is odd
--dwMilliseconds;
if(Hooks aren't dynamic)
ReEstablishApiHooks := TRUE;
}
If there wasn't unexpected exception in ApiWorks, ErrorAWSuccess is returned.
(this tells nothing about hooks application -> check UnhookAddresses.CurNoAddr)
Otherwise AH error codes
or AM error codes can be returned:
ErrorAMModule = lpszDll can't be found/loaded,
ErrorAMApi = lpszDll doesn't export ApiHookChain (via GetApiHookChain or ApiHookChain).
RemoteFunction for (h)EstablishApiHooks is implemented approx. as follows:
HMODULE Modules[256];
DWORD ModCnt = BuildModuleList(&Modules);
LPHMODULE ExcludeModules= NULL;
PAPI_HOOK AHChain;
PAPI_HOOK (__stdcall *GetAHChain)(DWORD CallerPID);
PAPI_HOOK (__stdcall *GetAHChain)(VOID);
if(*(LPDWORD)lpszDll == HOOKS_DYNAMIC)
AHChain = (PAPI_HOOK)lpszDll;
else {
if(GetModuleHandle(lpszDll) && !ReEstablishApiHooks)
return(ErrorAWSuccess); // lpszDll already present && not reestablish -> hooks are thought as already applied
else {
if(hHooks = LoadLibrary(lpszDll)) {
if(!(GetAHChain = GetProcAddress(hHooks, "GetApiHookChain"))) {
if(!(AHChain = GetProcAddress(hHooks, "ApiHookChain"))) {
return(ErrorAMApi); // Can't find AHChain
}
}
}
else {
AHChain = GetAHChain(CallerPID);
if(AHChain == NULL)
return(ErrorAMApi); // No AHChain
}
}
else {
return(ErrorAMModule); // Can't load lpszDll
}
}
}
while(AHChain->ModuleExport != HOOKS_END) {
if(AHChain->ModuleExport == HOOKS_DYNAMIC) {
ExcludeModules = AHChain.UnhookAddresses;
}
else {
if(AHChain->dwFlags == HOOK_ALL_SAFE) {
AHChain->dwFlags = HOOK_OVERWRITE;
if(ApplyHook(AHChain, AHChain->ModuleImport)) {
AHChain++;
continue;
}
else {
AHChain->dwFlags = HOOK_BY_NAME | HOOK_BY_ADDRESS;
AHChain->ModuleImport = ALL_MODULES;
}
}
if(AHChain->ModuleImport == ALL_MODULES) {
for(i=0; i<ModCnt; i++) {
ApplyHook(AHChain, Modules[i]);
}
}
else {
if(AHChain->dwFlags & (HOOK_BY_ADDRESS | HOOK_BY_NAME | HOOK_OVERWRITE | HOOK_RAW)) {
ApplyHook(AHChain, AHChain->ModuleImport);
}
}
}
AHChain++;
}
return(ErrorAWSuccess);
BOOL ApplyHooks (PAPI_HOOK ApiHook, LPSTR ModuleImport) {
if((ApiHook->dwFlags & (HOOK_BY_NAME | HOOK_BY_ADDRESS))
&& IsExcluded(GetModuleHandle(ModuleImport)))
return;
if((ApiHook->dwFlags & (HOOK_BY_NAME | HOOK_LOAD_IMPORT)) == (HOOK_BY_NAME | HOOK_LOAD_IMPORT))
LoadLibraryA(ModuleImport);
HookPlace = EvaluateHook(ApiHooks->dwFlags, ModBase);
ChangeBytes(ApiHook, HookPlace);
}
BOOL ChangeBytes(PAPI_HOOK ApiHook, PVOID HookPlace) {
if(IsNT)
goto StoreOld;
if(ApiHook->dwFlags & HOOK_RAW) //can't estimate if it lies in shared section
goto Check2GB;
if(HookPlace is in shared section)
if(!(ApiHook->dwFlags & HOOK_HARD))
return(FALSE);
Check2GB:
if(HookPlace >= 2GB)
if(!(ApiHook->dwFlags & HOOK_HARD))
return(FALSE);
StoreOld:
if(ApiHook->UnhookAddresses)
StoreOldBytes(ApiHook->UnhookAddresses, HookPlace);
return(WriteBytes(HookPlace));
}
ApiWorks understands these structures (all must lie within writeable memory):
a) For unhooking
typedef struct _ADDR_CONTENTS {
DWORD *ReturnWhere;
DWORD ReturnWhat;
} ADDR_CONTENTS, *PADDR_CONTENTS;
ReturnWhere contains address of place where ReturnWhat should be written.
typedef struct _API_UNHOOK {
DWORD MaxNoAddr;
DWORD CurNoAddr;
PADDR_CONTENTS WhereWhat;
} API_UNHOOK, *PAPI_UNHOOK;
MaxNoAddr is maximum number of ADDR_CONTENTS structures in WhereWhat field.
CurNoAddr (filled by AH) is the current number of filled and valid ADDR_CONTENTS
structures in WhereWhat field.
All API_UNHOOK members must be initialized.
b) For hooking
typedef struct _API_HOOK {
LPCSTR ModuleExport;
LPCSTR ApiNameOrOrd;
DWORD dwFlags;
LPCVOID ModuleImport;
PAPI_UNHOOK UnhookAddresses;
LPVOID HookAddress;
} API_HOOK, *PAPI_HOOK;
ModuleExport - pointer to ANSI name of module which exports wanted API.
Can be specified with PathTo. It doesn't have to be present
in Target.
Special values: MAIN_MODULE for main (.exe) module (mustn't
be used with HOOK_BY_NAME flag; specify main
module name instead).
HOOKS_END marks end of ApiHookChain.
HOOKS_DYNAMIC marks dynamic hooks.
If HOOK_RAW is set, ModuleExport can contain everything,
for example, pointer to symbol name.
Note: ApiWorks does not load ModuleExport.
ApiNameOrOrd - ordinal number (1..65535) of wanted API or
pointer to the ANSI name of wanted API.
It can be nonexisting (not exported by ModuleExport) name
or ordinal. It can be NULL only if ModuleExport doesn't exist.
If HOOK_RAW is set, ApiNameOrOrd must contain 32bit virtual
address (valid in Target).
dwFlags - specifies how to hook, see "C-ApiWorks-dwFlags.txt".
ModuleImport - if dwFlags contains HOOK_OVERWRITE, HOOK_RAW or HOOK_ALL_SAFE
flag, ModuleImport is thought as pointer to pointer-to-routine
-to-jump-to-original-API. If this pointer is initially NULL,
space for routine is allocated from process' heap. Space for
routine must be at least 32 bytes long.
- otherwise is is:
pointer to ANSI name of module which imports wanted API.
Can be specified with PathTo. If it isn't present in Target,
ModuleImport isn't hooked. However, you can preload
ModuleImport immediatelly before hooking via HOOK_LOAD_IMPORT
dwFlag.
Special values: MAIN_MODULE for main (.exe) module.
ALL_MODULES for all modules in Target.
UnhookAddresses pointer to API_UNHOOK structure for storing addresses for
unhooking.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -