http://pblog.ru/?p=317 described in detail.Hello, reader. Today, I will tell a rather effective way of intercepting API functions. It should not be assumed that if we want to intercept the API function, then we write either the trojan, the virus and some kind of contagion, with the interception of the API, many protective mechanisms are in place, the interception of the API functions is quite necessary and useful. To read this article with maximum benefit, it is necessary to at least initial knowledge of low-level programming and at least some knowledge of the Windows architecture. Okay, let's go.In this article, I will tell the most effective method of intercepting API functions is a cryising. Splying is the substitution of the functional code. Of course, there is another method of interception: editing the import table of the annex, editing the export table. I'll tell you the order.When you write in your annex like that. Function Func1(param:type):restype;stdcall;external ‘libname.dll’;You're importing a static function. The address of the function is described in the table of import of your annex (provided that the address of our function $7BC56010). address
... ...
$00405F56 7BC56010
... ...
And when a function is called, it happens.Push...
push...
call dword ptr [$00405F56]
Therefore, in order to intercept the function, we only need to change the value at $00405F56 to our own, and to challenge the original function to receive the address of the function through GetProcAddress. But the annex may also receive the address of the function through GetProcAddress and call for an intercepted function by a mine, interceptor. This method is imperfect. Let's What's all the crying? Our function is at $7C80B529 and let's say there's a code.7C80B529 8BFF mov edi, edi
7C80B52B 55 push ebp
7C80B52C 8BEC mov ebp, esp
7C80B52E 837D 08 00 cmp dword ptr ss:[ebp+8], 0
To intercept the function, we only need to rewrite the original code of the function so that it will transfer the control to our processor. In order to transfer control to our processor, only one injmp to the absolute address is sufficient to address our processor. This instruction will only take five Byte, the very opcode of this instruction ($E9) and the point of jump. This value is calculated. v=0-(s-d)
s - Composition of the next team
d - Required address for jmp, i.e. address of processor
If you change that formula a little, she'll look like that.v=d-FunctionAddress-5
Now, in every challenge, the task function will always be delegated to our processor. Now, how do we get an original function? When the interception is installed, we need to keep the first 5 byte. To call the original, we need to re-establish the beginning of the function and call it, then re-establish the interception. Explain the structure in which the first five byte functions will be retained:PFunctionRestoreData = ^ TFunctionRestoreData;
TFunctionRestoreData = packed record
Address:Pointer;
val1:Byte;
val2:DWORD;
end;
There is no need for a field address in this structure, in fact, for the field only to be more comfortable the interception. We call this " bridge " to the old function.Now write a function that will intercept:function SetCodeHook(ProcAddress, NewProcAddress: pointer; RestoreDATA:PFunctionRestoreData):boolean;
var
OldProtect, JMPValue:DWORD;
begin
Result:=False;
if not VirtualProtect(ProcAddress,5,PAGE_EXECUTE_READWRITE,OldProtect) then exit;
JMPValue := DWORD (NewProcAddress) - DWORD (ProcAddress) - 5;
RestoreDATA^.val1:= Byte(ProcAddress);
RestoreDATA^.val2:= DWORD(Pointer(DWORD(ProcAddress)+1)^);
RestoreDATA^.Address:=ProcAddress;
byte(ProcAddress^):=$ E9;
DWORD(Pointer(DWORD(ProcAddress)+1)):=JMPValue;
Result:=VirtualProtect(ProcAddress,5,OldProtect,OldProtect);
end;
We first set out access attributes to the functional code so that it can be rewritten. Then we'll figure it out for the jump. First, we keep the function in the record, then we rewrite the function. There are old access attributes at the end.Now write a function that will remove the interception:function UnHookCodeHook(RestoreDATA:PFunctionRestoreData):Boolean;
var
ProcAddress:Pointer;
OldProtect,JMPValue:DWORD;
begin
Result:=False;
ProcAddress:=RestoreDATA.Address;
if not VirtualProtect(ProcAddress,5,PAGE_EXECUTE_READWRITE,OldProtect) then exit;
Byte(ProcAddress^):=RestoreDATA.val1;
DWORD(Pointer(DWORD(ProcAddress)+1)):=RestoreDATA^.val2;
Result:=VirtualProtect(ProcAddress,5,OldProtect,OldProtect);
end;
I think it's all clear here-- just re-establishing the beginning of a cross-cutting function. The address of the overlapping function is taken from the structure by an index to which the function is transferred as the only parameter.Now write a function that will intercept by name of the function. function SetProcedureHook(ModuleHandle: HMODULE; ProcedureName : PChar; NewProcedureAddress :Pointer; RestoreDATA : PFunctionRestoreData) :Boolean;
var
ProcAddress:Pointer;
begin
ProcAddress:=GetProcAddress(ModuleHandle,ProcedureName);
Result:=SetCodeHook(ProcAddress,NewProcedureAddress,RestoreDATA);
end;
Let's go. The functions described above may be intercepted only in the current process. How do we intercept functions in other processes? The simplest method is to lock the DLL interceptor and, in the library function code, to intercept if DL is loaded and intercepted if it is discharged. There's another problem: how to get another process to download our DLL. The simplest solution is to create remote flows. It's all right now.The remote flow is created by CreateRemoteThread.HANDLE CreateRemoteThread(
HANDLE hProcess, / / hendle of process in which flow
LPSECURITY_ATTRIBUTES lpThreadAttributes,//security attributes
DWORD dwStackSize, / meter
LPTHREAD_START_ROUTINE lpStartAddress, / stream address
LPVOID lpParameter, / parameter for function
DWORD dwCreationFlags, // creation flags
LPDWORD lpThreadId / index to the variable in which the ID flow will be stored
);
The flow function shall have the following attributes:DWORD WINAPI ThreadFunc(PVOID pvPararn)
The function only has one parameter, it's a normal index. Now we'll analyze the situation... Thinking... shaving brains... LoadLibraryA has the same attributes. It accepts the index on the first symbol of the DLL file (the line shall end with the symbol #0). Consequently, the function of LoadLibraryA is entirely appropriate to enable it to act as a flow function. Since she's taking a line mark in her own process, we'll have to record our line and the name of the DLL file in the memory of someone else's process. This is done by the WriteProcessMemory function. That's her description.BOOL WriteProcessMemory(
HANDLE hProcess, /
LPVOID lpBaseAddress/ addressed to which
LPVOID lpBuffer, /
DWORD nSize, / number of byte for recording
LPDWORD lpNumberOfBytesWritten //number of actually written byte
);
The LoadLibraryA address of the functions of the LoadLibraryA is obtained by means of the GetProcAddress function as such a library of kernel32.dll and ntdll.dll will be loaded in all processes at all times at the same addresses, and the address received in the target area of our process will be effective and the target area of any other process. Now, we'll write a function that's putting your DLL into the target space of a different process. function LoadLibrary_Ex(ProcessID:DWORD;LibName:PChar):boolean;
var
pLL,pDLPath:Pointer;
hProcess,hThr:THandle;
LibPathLen,_WR,ThrID:DWORD;
begin
Result:=False;
LibPathLen:=Length(string(LibName));
hProcess:=OpenProcess(PROCESS_ALL_ACCESS,false,ProcessID);
if hProcess=0 then exit;
pDLPath:=VirtualAllocEx(hProcess,0,LibPathLen+1,MEM_COMMIT,PAGE_READWRITE);
if DWORD(pDLPath)=0 then exit;
pL:=GetProcAddress(GetModuleandle(kernel32),'LoadLibraryA');
WriteProcessMemory(hProcess,pDLPath,LibName,LibPathLen+1,_WR);
hThr:=CreateRemoteThread(hProcess,0.0,pLLL,pDLPath,0,ThrID);
if hThr=0 then exit;
Result:=CloseHandle(hProcess);
end;
So we loaded our DLL into a different process. In fact, the introduction of your code into other people's processes is a different story and requires a separate article. The above example is the simplest way to get into someone else's process. The normal process is not allowed to change the memory of systemic processes, such as winlogon.exe, lsass.exe, sms.exe, csrss.exe, etc., which requires SeDebugPrivilege. There is an EnableDebugPrivilege function attached to the article, which includes this privilege for the current process.Come on. Now we've learned to load our DLL into a different process. But for good effect, we need to intercept DLL in all the system processes. But how do you do that? It is possible to simply list the processes through ToolHelp32 and download their DLL into every process found. It is not acceptable, however, that the functions will not be intercepted in the newly established processes. But you can list the processes every second, which is also unacceptable and a very long story. The simplest method is to take advantage of what the khuk mechanism provides us. When we put a global Hook using the SetWindowsHookEx function, the DLL, which has a Huk processor function, is loaded into all processes that receive messages from the system through the GetMessage and PeekMessage functions. The DLL card with the interception of functions would look like that. library HideDLL;
uses
Windows,
ExtendedAPIFunctions,
apihooktools;
?
const
MutexName='_API_HOOK';
function MsgProc(code:DWORD;wParam,lparam:DWORD):DWORD;stdcall;
begin
Result:=CallNextHookEx(SH,code,wParam,lparam);
end;
procedure SetWindowsHook(e:Boolean); stdcall;
var
M:THandle;
begin
if e then
begin
M:=CreateMutex(0,false,MutexName);
if GetLastErrorERROR_ALREADY_EXISTS then
begin
SH:=SetWindowsHookEx(WH_GETMESSAGE,@MsgProc,HInstance,0);
MutexHandle:=M;
end else
CloseHandle(M);
end
else
begin
UnhookWindowsHookEx(SH);
CloseHandle(MutexHandle);
end;
end;
procedure DLLEntryPoint(dwReason:DWord);
begin
case dwReason of
DL_PROCESS_ATTACH:
begin
// StopProcess(GetCurrentProcessId);
SetWindowsHook(true);
SetProcedureHook(GetModuleHandle('ntdll.dll'),'ZwQuerySystemInformation',@NewSystemFunction,@SystemFunctionBridge);
/ ResumeProcess(GetCurrentProcessId);
end;
DL_PROCESS_DETACH:
begin
// StopProcess(GetCurrentProcessId);
UnHookCodeHook(@SystemFunctionBridge);
SetWindowsHook(false);
/ResumeProcess(GetCurrentProcessId);
end;
end;
end;
begin
DllProc:= @DLLEntryPoint;
DLLEntryPoint(DL_PROCESS_ATTACH);
end.
In order to intercept API in all processes (all GUI processes), it is sufficient to simply download our DLL. It's enough to write this code: LoadLibrary(pchar(ExtractFileDir(Application.ExeName)+'+'DLL.dll')
One precautionary measure should also be borne in mind when installing and removing the interception of functions: all other flows of the ongoing process must be stopped, as at the time of interception, other flows may give rise to a desired function and this will lead to unpredictable consequences.There's a headline file for Delphi in the feeding archive.That's all for today. There is also an example in the archives of the lsass.exe process. http://pblog.ru/wp-content/uploads/samplehideprocess.zip