📄 b-modworks.txt
字号:
ModWorks is very simple Scout that allows finding presence of/unloading/loading
given module and calling a function residing in that module.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
All ModWorks 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 ModWorks functions can have (including zero terminator)
max. MAX_PATH characters. If it has more, ModWorks returns ErrorAHException.
For successful ModWorks execution, KERNEL32.dll mustn't have altered export entries
for GetModuleHandleA, FreeLibrary, LoadLibraryA, GetProcAddress. If they were altered,
ModWorks 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 (un)load. Typically set
Read & Execute for Everyone. It is important for intersession loadings. The same applies
onto imported modules (e.g. ApiHooks.dll, PrcWorks.dll, ..).
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
DWORD __stdcall IsModuleLoaded(PRCINFO pRCI, LPCTSTR lpszDll, DWORD ProcessId, LONG dwMilliseconds);
DWORD __stdcall hIsModuleLoaded(PRCINFO pRCI, LPCTSTR lpszDll, HANDLE hProcess, LONG dwMilliseconds);
RemoteFunction for (h)IsModuleLoaded is implemented as follows:
RFResult = GetModuleHandle(lpszDll);
Return codes:
All AH error codes
or
RFResult:
== NULL - module isn't present in Target.
!= NULL - module base in Target (module is present in Target).
9x: TH32 Module32First/Next (faster) instead of IsModuleLoaded should be used.
2K: PSAPI's EnumModules (probably faster) should be used.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
DWORD __stdcall UnloadModule(PRCINFO pRCI, LPCTSTR lpszDll, DWORD ProcessId, LONG dwMilliseconds, DWORD HowManyTimes);
DWORD __stdcall hUnloadModule(PRCINFO pRCI, LPCTSTR lpszDll, HANDLE hProcess, LONG dwMilliseconds, DWORD HowManyTimes);
These functions try to unload lpszDll from ProcessId/hProcess during dwMilliseconds
HowManyTimesx.
RemoteFunction for (h)UnloadModule is implemented as follows:
RFResult = GetModuleHandle(lpszDll);
while((int)(--HowManyTimes) >= 0) {
FreeLibrary(RFResult);
RFResult = GetModuleHandle(lpszDll);
}
Parameters:
HowManyTimes - how many times to call FreeLibrary (how many times to unload).
Return codes:
All AH error codes
or
RFResult:
== NULL - module isn't present in Target.
!= NULL - module base in Target (module is present in Target).
Note:
NT only: Statically (at process startup) loaded modules and modules with RefCount > 65534
can't be unloaded.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
DWORD __stdcall LoadAndCall(PRCINFO pRCI, LPCTSTR lpszDll, DWORD ProcessId, LONG dwMilliseconds, DWORD HowManyTimes, LPCSTR ApiNameOrOrd, DWORD nArgs, LPVOID pArgs);
DWORD __stdcall hLoadAndCall(PRCINFO pRCI, LPCTSTR lpszDll, HANDLE hProcess, LONG dwMilliseconds, DWORD HowManyTimes, LPCSTR ApiNameOrOrd, DWORD nArgs, LPVOID pArgs);
RemoteFunction for (h)LoadAndCall is implemented as follows:
if(HowManyTimes == 0)
RFResult = GetModuleHandle(lpszDll);
else {
while(HowManyTimes--) {
RFResult = LoadLibrary(lpszDll);
}
}
if(RFResult == NULL)
RFResult = ErrorAWModule;
else
if(pFunc = GetProcAddress(RFResult, ApiNameOrOrd)) {
RFResult = pFunc(pArgs[0], ... pArgs[nArgs-1]);
}
else
RFResult = ErrorAWApi;
Parameters:
ApiNameOrOrd - name or ordinal of function to call (assembly language level: function
can destroy all registers but EBP).
Supported are:
1) C family calling conventions (cdecl, stdcall (WINAPI), syscall),
2) PASCAL family calling conventions (BASIC, FORTRAN),
3) fastcall (ECX = pArgs[0], EDX = pArgs[1]),
4) COM (or C++ member function) calling convention (this in ECX; ECX = pArgs[0]),
5) Delphi calling convention (PASCAL order, EAX = pArgs[0], EDX = pArgs[1], ECX = pArgs[2]).
nArgs - can be in <0..LACMaxArgs> interval. If it's higher, (h)LoadAndCall returns ErrorAHException.
Default calling convention is 1). OR nArgs with one of the following constants
to specify special calling convention:
LAC_PASCAL, LAC_FASTCALL, LAC_COMCALL, LAC_DELPHI.
nArgs can be greater then the real count of parameters for function.
nArgs determines the size of user input buffer that is copied into Target.
pArgs - pointer to (or array of) parameters in order it should be passed to function:
pArgs[3] = {1,2,3}; LoadAndCall(,...,"Function", 3, pArgs);
calls Function as Function(1,2,3);
Before passing pArgs to RemoteFunction the following replacement/s is/are made:
for(i=0; i<nArgs; i++)
if(pArgs[i] == LACThreadBodyAlias)
pArgs[i] = CurrentThreadBody;
Note:
lpszDll is loaded, DllMain gets DLL_PROCESS_ATTACH followed by DLL_THREAD_DETACH notification
for the same thread.
Many APIs require calling thread to be Win32. Threads into native processes and
into processes in other terminal sessions are native, not Win32. How to make them
Win32? See F-Advanced.txt.
Do not confuse LoadAndCall with (obsolete) Win32 function LoadModule.
!!! When lpszDll is not/loaded present in Target LAC returns ErrorAMModule, not NULL !!!
LAC buffer and pointers
-----------------------
LAC buffer starts at ThreadBody+LACMEMOffset and its size is LACMEMSize.
User can pass max. LACMaxArgs to RemoteFunction. LAC buffer contains copy
of pArgs.
ThreadBody+000000000000 ----------
reserved
+LACMEMOffset ----------
pArgs[0], pArgs[1], ..pArgs[LACMaxArgs-1]
+LACMEMSize ----------
----------------------------------
Use LACMEMPointer (alias) to address given argument:
LACMEMPointer+00 points to pArgs[00];
LACMEMPointer+80 points to pArgs[20];
Using LACMEMPointer:
--------------------
a)
RCINFO lRCI;
memcpy(&lRCI, GetDefaultRCInfo(), sizeof(RCINFO));
lRCI.RCFlags = RC_FL_OWNFREE;
#define nGFNAPars ((sizeof(DWORD)+sizeof(LPSTR)+MAX_PATH*sizeof(CHAR))/sizeof(DWORD))
DWORD GFNAPars[nGFNAPars] = {NULL, LACMEMPointer+00, MAX_PATH};
LoadAndCall(&lRCI, DLLName, PID, INFINITE, 0, _T("GetModuleFileNameA"), nGFNAPars, GFNAPars);
CHAR ModFileNameA[MAX_PATH];
ReadProcessMemory(lRCI.hProcess, (LPVOID)((DWORD)lRCI.ThreadBody+LACMEMOffset+00), ModFileNameA, MAX_PATH, NULL);
lRCI.RtlFreeMem(lRCI.hProcess, lRCI.ThreadBody);
CloseHandle(lRCI.hProcess);
b)
DWORD SetConsoleTitleAPars[5] = {LACMEMPointer+sizeof(DWORD), 'lleH', 'oC o', '!red', '\0'};
LoadAndCall(NULL, DLLName, PID, INFINITE, 0, _T("SetConsoleTitleA"), 5, SetConsoleTitleAPars);
Using LACMEMPointer:
--------------------
DWORD SetConsoleTitleAPars[5] = {LACSTKPointer+sizeof(DWORD), 'lleH', 'oC o', '!red', '\0'};
LoadAndCall(NULL, DLLName, PID, INFINITE, 0, _T("SetConsoleTitleA"), 5, SetConsoleTitleAPars);
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
See:
Examples\B-ModWorks.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -