I am trying to hook a user-defined function of a program written in Delphi using C++ and Detours library. (DLL Injection)
However, I can't hook it because Delphi's and C++'s function calling conventions don't match.
Delphi uses the fastcall function calling convention, and C++ also provides a fastcall function calling convention.
However, Delphi's fastcall stores its arguments sequentially on EAX, EDX, ECX, and the stack, whereas C++'s fastcall stores its arguments sequentially on ECX, EDX, and stack. (This is because there is no standard for fastcall.)
Due to these differences, I have no way to get the arguments stored in EAX.
How can I solve this problem?
(This article has been translated by Google Translate.)
< dllmain.cpp >
#include "pch.h"
typedef void(__fastcall* ORGFP)(char); //Prototype of function to hook (reverse engineering)
ORGFP originFunc1 = (ORGFP)((DWORD)GetModuleHandle(NULL) + 0x2B2F20); //Image base of target process + offset of function to hook
ORGFP originFunc2 = (ORGFP)((DWORD)GetModuleHandle(NULL) + 0x2B2A20);
DWORD WriteLog(LPCTSTR lpszFormat, ...) {
TCHAR szLog[512];
DWORD dwCharsWritten;
va_list args;
va_start(args, lpszFormat);
_vstprintf_s(szLog, 512, lpszFormat, args);
va_end(args);
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), szLog, _tcslen(szLog), &dwCharsWritten, NULL);
return dwCharsWritten;
}
void __fastcall DetourFunc1(char on) {
WriteLog(TEXT("Function called : BlockInternet(%d)\n"), on);
return originFunc1(on);
}
void __fastcall DetourFunc2(char on) {
WriteLog(TEXT("Function called : BlockInputDevices(%d)\n"), on);
return originFunc2(on);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (DetourIsHelperProcess())
return TRUE;
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
AllocConsole();
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)originFunc1, DetourFunc1);
DetourAttach(&(PVOID&)originFunc2, DetourFunc2);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
FreeConsole();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)originFunc1, DetourFunc1);
DetourDetach(&(PVOID&)originFunc2, DetourFunc2);
DetourTransactionCommit();
break;
}
return TRUE;
}
< pch.cpp >
#include "pch.h"
< pch.h >
#ifndef PCH_H
#define PCH_H
#include "framework.h"
#include <stdio.h>
#include <stdarg.h>
#include <tchar.h>
#include <detours.h>
#endif
< framework.h >
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
I solved this problem using __declspec(naked)! Thanks to everyone who helped me!
#include <iostream>
#include <Windows.h>
#include <detours.h>
using namespace std;
__declspec(naked) void __fastcall originFunction(char arg) {
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}
__asm {
mov byte ptr [arg], al
}
cout << (int)arg << endl;
__asm {
mov esp, ebp
pop ebp
ret
}
}
typedef void(__fastcall* FP)(char);
FP originFunctionPointer = originFunction;
__declspec(naked) void __fastcall detourFunction(char arg) {
__asm {
push ebp
mov ebp, esp
sub esp, __LOCAL_SIZE
}
__asm {
mov byte ptr [arg], al
}
cout << (int)arg << endl;
arg = 0;
__asm {
mov al, byte ptr [arg]
call dword ptr [originFunctionPointer]
}
__asm {
mov esp, ebp
pop ebp
ret
}
}
int main() {
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)originFunctionPointer, detourFunction);
DetourTransactionCommit();
__asm {
mov al, 1h
call dword ptr [originFunction]
}
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)originFunctionPointer, detourFunction);
DetourTransactionCommit();
return 0;
}
As per wikipedia:
Borland register
Evaluating arguments from left to right, it passes three arguments via EAX, EDX, ECX. Remaining arguments are pushed onto the stack, also left to right.[12] It is the default calling convention of the 32-bit compiler of Delphi, where it is known as register. This calling convention is also used by Embarcadero's C++Builder, where it is called __fastcall.[13] In this compiler, Microsoft's fastcall can be used as __msfastcall.[14]
GCC and Clang can be made to use a similar calling convention by using __stdcall with the regparm function attribute or the -mregparm=3 switch. (The stack order is inverted.) It is also possible to produce a caller clean-up variant using cdecl or extend this to also use SSE registers.[15] A cdecl-based version is used by the Linux kernel on i386 since version 2.6.20 (released February 2007).
https://en.wikipedia.org/wiki/X86_calling_conventions#Borland_register
Related
I made a WOW64 syscall hook for the `NtCreateSection` function using the following code:
#include "Funcs.h"
#include <cstdio>
#include <Windows.h>
const int PAGE_SIZE = 0x1000;
const int SYSCALL_INTERCEPT = 0x4A;
const int NUM_WOW64_BYTES = 0x9;
using pNtCreateSection =
NTSTATUS (NTAPI*)(PHANDLE SectionHandle, ULONG DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes,
PLARGE_INTEGER MaximumSize, ULONG PageAttributess, ULONG SectionAttributes, HANDLE FileHandle);
pNtCreateSection NtCreateSection = nullptr;
DWORD_PTR dwWow64Address = 0;
LPVOID lpJmpRealloc = nullptr;
ULONG SectionAttributes;
void __declspec(naked) NtCreateSectionHook()
{
__asm
{
pushad
}
fprintf(stderr, "NtCreateSectionHook called !\n");
__asm
{
popad
jmp lpJmpRealloc
}
}
DWORD_PTR __declspec(naked) GetWow64Address()
{
__asm
{
mov eax, dword ptr fs:[0xC0]
ret
}
}
void __declspec(naked) Wow64Trampoline()
{
__asm
{
cmp eax, SYSCALL_INTERCEPT
jz NtCreateSectionHook
jmp lpJmpRealloc
}
}
LPVOID CreateNewJump(const DWORD_PTR dwWow64Address)
{
lpJmpRealloc = VirtualAlloc(nullptr, PAGE_SIZE, MEM_RESERVE | MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
(void)memcpy(lpJmpRealloc, (const void *)dwWow64Address, NUM_WOW64_BYTES);
return lpJmpRealloc;
}
void EnableWow64Redirect(const DWORD_PTR dwWow64Address, const LPVOID lpNewJumpLocation)
{
unsigned char trampolineBytes[] =
{
0x68, 0xDD, 0xCC, 0xBB, 0xAA, /*push 0xAABBCCDD*/
0xC3, /*ret*/
0xCC, 0xCC, 0xCC /*padding*/
};
memcpy(&trampolineBytes[1], &lpNewJumpLocation, sizeof(DWORD_PTR));
WriteJump(dwWow64Address, trampolineBytes, sizeof trampolineBytes);
}
void WriteJump(const DWORD_PTR dwWow64Address, const void *pBuffer, size_t ulSize)
{
DWORD dwOldProtect = 0;
(void)VirtualProtect(reinterpret_cast<LPVOID>(dwWow64Address), PAGE_SIZE, PAGE_EXECUTE_READWRITE, &dwOldProtect);
(void)memcpy(reinterpret_cast<void *>(dwWow64Address), pBuffer, ulSize);
(void)VirtualProtect(reinterpret_cast<LPVOID>(dwWow64Address), PAGE_SIZE, dwOldProtect, &dwOldProtect);
}
int main(int argc, char *argv[])
{
const auto hModule = GetModuleHandle(L"ntdll.dll");
NtCreateSection = reinterpret_cast<pNtCreateSection>(GetProcAddress(hModule, "NtCreateSection"));
dwWow64Address = GetWow64Address();
const auto lpNewJumpLocation = CreateNewJump(dwWow64Address);
EnableWow64Redirect(dwWow64Address, static_cast<LPVOID>(Wow64Trampoline));
//Test syscall
HANDLE hSection;
NtCreateSection(&hSection, SECTION_ALL_ACCESS, nullptr, nullptr, PAGE_EXECUTE_READWRITE, SEC_COMMIT | SEC_NOCHANGE, nullptr);
getchar();
return 0;
}
The code works fine until I change the hooked function to this
void __declspec(naked) NtCreateSectionHook()
{
__asm
{
pushad
mov eax, [esp + 28]
mov SectionAttributes, eax
}
fprintf(stderr, "NtCreateSectionHook called !\n");
if ((SectionAttributes & SEC_NOCHANGE) != 0)
{
fprintf(stderr, "SEC_NOCHANGE found !\n");
}
__asm
{
popad
jmp lpJmpRealloc
}
}
The problem in my code is that the pushad instruction messes with the esp therefore I can't access the stack anymore and if I don't use pushad/popap the app crashes since I'm messing up with the stack then jumping to the real function address.
The argument I wanna access and change is the 6th argument of NtCreateSection
function.
pushad does not prevent you from accessing the stack. pushad pushes 32 bytes (8 registers, 4 bytes each) into the stack, hence, any offset after pushad should be corrected by adding 32.
I tried to test the RegCreateKeyEx call using asm inline.
This is the code :
long regkey(HKEY lnKey, LPCTSTR lpsub, DWORD rise, LPTSTR lpc, DWORD dwopt, REGSAM sd, LPSECURITY_ATTRIBUTES lpas, HKEY * const &llkey, DWORD * const &dwDisposition)
{
__asm
{
lea eax, dwDisposition
push eax // put eax at the top of the stack
lea eax, llkey
push eax
lea eax, lpas
push eax
lea eax, sd
push eax
lea eax, dwopt
push eax
lea eax, lpc
push eax
lea eax, rise
push eax
lea eax, lpsub
push eax
lea eax, lnKey
push eax
call DWORD ptr RegCreateKeyEx
}
return;
}
int main()
{
HKEY lnKey;
LPCTSTR lpsub;
DWORD rise;
LPTSTR lpc;
DWORD dwopt;
REGSAM sd;
LPSECURITY_ATTRIBUTES lpas;
HKEY llkey;
DWORD dwDisposition;
long ret0 = regkey(HKEY_CURRENT_USER, TEXT(linkey.c_str()), 0, NULL, 0, KEY_WRITE, NULL, &llkey, &dwDisposition);
printf("CREATE %d\n", ret0);
return 0;
}
However, it returns error 87 (INVALID ARGUMENT).
The linkey.c_str () variable contains the string "Software\\Microsoft\\Windows\\CurrentVersion\\Run\\" path and passes it correctly because I tried to use it directly by calling directly the RegCreateKeyEx (HKEY_CURRENT_USER,
TEXT (linkey.c_str ()),
0, NULL, 0,
KEY_WRITE, NULL,
& Llkey, & dwDisposition) ad it's all OK
Where am I wrong in use asm inline?
If you wrote the code in C++, like so:
LONG regkey(HKEY lnKey, LPCTSTR lpsub, DWORD rise, LPTSTR lpc, DWORD dwopt, REGSAM sd, LPSECURITY_ATTRIBUTES lpas, HKEY * const &llkey, DWORD * const &dwDisposition)
{
return RegCreateKeyEx(lnKey, lpsub, rise, lpc, dwopt, sd, lpas, llkey, dwDisposition);
}
then you could compile it using the /FA switch, as advised in the comments, to get the compiler to generate an assembly listing of the code it would generate. Alternatively, you could compile it and then break in, using the debugger to show the disassembly of the actual binary. Either way, you'd see the following assembly code being generated by the compiler:
mov eax, DWORD PTR [esp+36] ; dwDisposition
push DWORD PTR [eax]
mov eax, DWORD PTR [esp+36] ; llkey
push DWORD PTR [eax]
push DWORD PTR [esp+36] ; lpas
push DWORD PTR [esp+36] ; sd
push DWORD PTR [esp+36] ; dwopt
push DWORD PTR [esp+36] ; lpc
push DWORD PTR [esp+36] ; rise
push DWORD PTR [esp+36] ; lpsub
push DWORD PTR [esp+36] ; lnKey
call DWORD PTR RegCreateKeyEx
ret 0
So, the inline assembly should be:
LONG regkey(HKEY lnKey, LPCTSTR lpsub, DWORD rise, LPTSTR lpc, DWORD dwopt, REGSAM sd, LPSECURITY_ATTRIBUTES lpas, HKEY * const &llkey, DWORD * const &dwDisposition)
{
__asm
{
mov eax, DWORD PTR [dwDisposition]
push DWORD PTR [eax]
mov eax, DWORD PTR [llkey]
push DWORD PTR [eax]
push DWORD PTR [lpas];
push DWORD PTR [sd];
push DWORD PTR [dwopt];
push DWORD PTR [lpc];
push DWORD PTR [rise];
push DWORD PTR [lpsub]
push DWORD PTR [lnKey]
call DWORD PTR RegCreateKeyEx
} // return value is left in EAX
}
which is pretty darn easy. You don't need to worry about calculating offsets from the stack pointer, because the inline assembler supports the use of C++ variables. There is never a need for a LEA instruction. In fact, the LEA instruction is wrong, because it causes you to pass pointers as parameters to the RegCreateKeyEx function, instead of the values themselves, which is why you were getting error code 87, "Invalid parameter".
The only complicated thing is the way the dwDisposition and llkey parameters are handled. First, the address has to be loaded into a register (EAX), and then that address is dereferenced as it is pushed onto the stack. This additional level of indirection is necessary because you passed these parameters as references to pointers. I have no idea why you've chosen to do that, but because you did, the reference has to be dereferenced. (Under the hood, a C++ compiler implements references like pointers.)
However, I have no idea why you would actually write this code in inline assembly. There is absolutely no reason to do so; it isn't buying you anything, it's just making things more complicated to write and maintain. It's also costing you something in performance. Above, I showed what a C++ compiler would generate for the function call. Here is what the compiler generates when you use inline assembly:
push ebp
mov ebp, esp
mov eax, DWORD PTR _dwDisposition$[ebp]
push DWORD PTR [eax]
mov eax, DWORD PTR _llkey$[ebp]
push DWORD PTR [eax]
push DWORD PTR _lpas$[ebp]
push DWORD PTR _sd$[ebp]
push DWORD PTR _dwopt$[ebp]
push DWORD PTR _lpc$[ebp]
push DWORD PTR _rise$[ebp]
push DWORD PTR _lpsub$[ebp]
push DWORD PTR _lnKey$[ebp]
call DWORD PTR RegCreateKey
pop ebp
ret 0
Notice the extra prologue and epilogue instructions that are made necessary by the use of inline assembly, since the compiler has no idea what you are actually doing inside of the inline assembly and therefore has to compensate for it by setting up and tearing down a stack frame. It isn't a massive performance cost or anything, but again, it's completely pointless.
Your follow-up question/problem (from a comment and an answer you posted) makes no sense to me. You shouldn't need any sort of exception handler, and since you didn't quote the exact error message you're getting, I have no idea what it might be trying to say. It is likely that the problem relates to strtemp, whose declaration you don't show us. Since you said you are calling the ANSI version of RegCreateKeyEx, strtemp should be a pointer to a char buffer, terminated with a NUL character. Also, the next parameter you are passing to RegSetValueEx is wrong: cbData must include the terminating NUL character, so this should properly be strlen(strtemp) + 1.
Other problems with your code include the fact that there is absolutely no error checking. If the attempt to create the registry key fails, then you should not attempt to write into it, nor should you attempt to close it.
Also, there is never a reason in the year 2017 to call the ANSI version of a Windows API function. Everything has been Unicode internally for almost two decades, and your code needs to get with the program. This means using strings consisting of wchar_t characters.
I know it's a long post but it's mostly code and pictures, it's a quick read! First of all, here is what I'm trying to do:
I'm trying to execute a BYTE array in a detoured function in order to go back to the original code as if I didn't detour anyhting Here is my code:
DllMain (DetourAddress is all that matter):
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
AllocConsole();
freopen("CONOUT$", "w", stdout);
DetourAddress((void*)HookAddress, (void*)&DetourFunc);
case DLL_PROCESS_DETACH:
FreeConsole();
break;
}
return TRUE;
}
DetourAddress (code is self-explanatory, I think):
void DetourAddress(void* funcPtr, void* hook)
{
// write jmp
BYTE cmd[5] =
{
0xE9, //jmp
0x00, 0x00, 0x00, 0x00 //address
};
// make memory readable/writable
DWORD dwProtect;
VirtualProtect(funcPtr, 5, PAGE_EXECUTE_READWRITE, &dwProtect);
// read bytes about to be replaced
ReadProcessMemory(GetCurrentProcess(), (LPVOID)funcPtr, mem, 5, NULL);
// write jmp in cmd
DWORD offset = ((DWORD)hook - (DWORD)funcPtr - 5); // (dest address) - (source address) - (jmp size)
memcpy(&cmd[1], &offset, 4); // write address into jmp
WriteProcessMemory(GetCurrentProcess(), (LPVOID)funcPtr, cmd, 5, 0); // write jmp
// reprotect
VirtualProtect(funcPtr, 5, dwProtect, NULL);
}
DetourFunc:
_declspec(naked) void DetourFunc()
{
__asm
{
PUSHFD
PUSHAD
}
printf("function detoured\n");
__asm
{
POPAD
POPFD
}
// make memory readable/writable
DWORD dwProtect;
VirtualProtect(mem, 6, PAGE_EXECUTE_READWRITE, &dwProtect);
pByteExe();
// reprotect
VirtualProtect(mem, 6, dwProtect, NULL);
__asm
{
jmp HookReturnAddress
}
}
And finaly the global variables, typedef for pByteExe() and includes:
#include <Windows.h>
#include <cstdio>
DWORD HookAddress = 0x08B1418,
HookReturnAddress = HookAddress+5;
typedef void ( * pFunc)();
BYTE mem[6] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0xC3 };
pFunc pByteExe = (pFunc) &mem
As you can see in DetourFunc, I'm trying to execute my byte array (mem) directly. Using OllyDbg, this gets me there:
Which is exactly the bytes I'm trying to execute. Only problem is that it gives me an Access violation error when executing... Any idea why? I would have thought "VirtualProtect(mem, 5, PAGE_EXECUTE_READWRITE, &dwProtect);" would have made it safe to access... Thanks for your help!
EDIT: I just realized something wierd was happening... when I "Step into" with ollydbg, the mem instructions are correct, but as soon as I scroll a little, they change back to this:
Any idea why?
You've forgot the module offset...
DWORD module = (DWORD)GetModuleHandle(NULL);
DWORD real_address = module + (DWORD)ADDRESS;
ADDRESS have to of course relative to your module. (The module offset isn't allways the same)
And btw. why you take WriteProcessMemory, when you inject your DLL? A simple memcpy is enought...
So i am currently learning about hooking and injection and build a little test application for myself. What i am doing in there is:
Allocating some memory inside the process (using VirtualAllocEx)
Writing code to this code-cave (using WriteProcessMemory)
Hooking a function inside the app to jump to this code-cave
Now i have some problems which i am unsure of why they occur.
My code for creating the cave is this:
DWORD procID = GetCurrentProcessId();
HANDLE procHandle = OpenProcess((PROCESS_VM_WRITE | PROCESS_VM_OPERATION), false, procID);
if (procHandle == NULL) {
std::cout << "OpenProcess failed..." << std::endl;
return -1;
}
DWORD leng = (unsigned int)dynASM_end - (unsigned int)dynASM;
leng += 270;
LPVOID allocAddr = VirtualAllocEx(procHandle, NULL, leng, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
std::cout << "BaseAddr: " << allocAddr << std::endl;
int check = WriteProcessMemory(procHandle, (void*)((char*)allocAddr + 0x10E), dynASM, leng - 270, NULL);
unsigned int bExec = 1;
check = WriteProcessMemory(procHandle, allocAddr, &bExec, sizeof(unsigned int), NULL);
if (check) {
std::cout << "Successfully written asm to process!" << std::endl;
}
Now this is very basic. VirtualAllocEx always returns 0x00030000, is this possible?
This is my simple assembly code:
void testCall()
{
std::cout << "Hook worked!" << std::endl;
}
__declspec(naked) void dynASM()
{
__asm {
push ebp
mov ebp, esp
call testCall
mov esp, ebp
pop ebp
ret
}
}
__declspec(naked) void dynASM_end()
{
}
I believe i can call the function testCall this way, can't i? This is the code which i put into the codecave as you can see above.
Now i have a offset to a function inside another class in which i want to hook. This function only consists of:
__declspec(naked) void Core::HookFunc()
{
__asm {
mov edi, edi
push ebp
mov ebp, esp
mov esp, ebp
pop ebp
ret
}
}
And i try to hook like this:
DWORD hookFuncOffset = 0x14510;
DWORD jumpTo = (DWORD)((char*)allocAddr + 0x10E);
DWORD baseAddr = (DWORD)GetModuleHandle(NULL);
BYTE* finalAddr = (BYTE*)((DWORD)baseAddr + hookFuncOffset);
DWORD oldProtect, bkpProtect, relAdr;
VirtualProtect(finalAddr, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
relAdr = (DWORD)(jumpTo - (DWORD)finalAddr) - 5;
*finalAddr = 0xE9;
*((DWORD*)finalAddr + 0x1) = relAdr;
VirtualProtect(finalAddr, 5, oldProtect, &bkpProtect);
allocAddr is the address for the code-cave i have allocated above.
Now while debugging it i can see that relAddr is 0xFFFABBF9 which seems really high to me. But if i look into the disassembly view of Visual Studio the jmp created leads to 0xF9939B14 which leads to an Access Violation Exception. I would believe that even if the jmp would lead to the "correct" address it would also throw an Exception. What am i doing wrong?
Debugging with visual studio 2005 The following Error Displayed :
Unhandled exception at 0x00000000 in procexp.exe: 0xC0000005: Access
violation reading location 0x00000000.
And Thread Information:
2704 Win32 Thread 00000000 Normal 0
extern "C" VDLL2_API BOOL WINAPI MyTerminateProcess(HANDLE hProcess,UINT uExitCode)
{
SetLastError(5);
return FALSE;
}
FARPROC HookFunction(char *UserDll,FARPROC pfn,FARPROC HookFunc)
{
DWORD dwSizeofExportTable=0;
DWORD dwRelativeVirtualAddress=0;
HMODULE hm=GetModuleHandle(NULL);
FARPROC pfnOriginalAddressToReturn;
PIMAGE_DOS_HEADER pim=(PIMAGE_DOS_HEADER)hm;
PIMAGE_NT_HEADERS pimnt=(PIMAGE_NT_HEADERS)((DWORD)pim +
(DWORD)pim->e_lfanew);
PIMAGE_DATA_DIRECTORY
pimdata=(PIMAGE_DATA_DIRECTORY)&(pimnt->OptionalHeader.DataDirectory);
PIMAGE_OPTIONAL_HEADER pot=&(pimnt->OptionalHeader);
PIMAGE_DATA_DIRECTORY
pim2=(PIMAGE_DATA_DIRECTORY)((DWORD)pot+(DWORD)104);
dwSizeofExportTable=pim2->Size;
dwRelativeVirtualAddress=pim2->VirtualAddress;
char *ascstr;
PIMAGE_IMPORT_DESCRIPTOR
pimexp=(PIMAGE_IMPORT_DESCRIPTOR)(pim2->VirtualAddress + (DWORD)pim);
while(pimexp->Name)
{
ascstr=(char *)((DWORD)pim + (DWORD)pimexp->Name);
if(strcmpi(ascstr,UserDll) == 0)
{
break;
}
pimexp++;
}
PIMAGE_THUNK_DATA
pname=(PIMAGE_THUNK_DATA)((DWORD)pim+(DWORD)pimexp->FirstThunk);
LPDWORD lpdw=&(pname->u1.Function);
DWORD dwError=0;
DWORD OldProtect=0;
while(pname->u1.Function)
{
if((DWORD)pname->u1.Function == (DWORD)pfn)
{
lpdw=&(pname->u1.Function);
VirtualProtect((LPVOID)lpdw,sizeof(DWORD),PAGE_READWRITE,&OldProtect);
pname->u1.Function=(DWORD)HookFunc;
VirtualProtect((LPVOID)lpdw,sizeof(DWORD),PAGE_READONLY,&OldProtect);
return pfn;
}
pname++;
}
return (FARPROC)0;
}
FARPROC CallHook(void)
{
HMODULE hm=GetModuleHandle(TEXT("Kernel32.dll"));
FARPROC fp=GetProcAddress(hm,"TerminateProcess");
HMODULE hm2=GetModuleHandle(TEXT("vdll2.dll"));
FARPROC fpHook=GetProcAddress(hm2,"MyTerminateProcess");
dwAddOfTerminateProcess=HookFunction("Kernel32.dll",fp,fpHook);
if(dwAddOfTerminateProcess == 0)
{
MessageBox(NULL,TEXT("Unable TO Hook Function."),TEXT("Parth"),MB_OK);
}
else
{
MessageBox(NULL,TEXT("Success Hooked."),TEXT("Parth"),MB_OK);
}
return 0;
}
Thanks in advance for any help.
004118AC mov esi,esp
004118AE push 0
004118B0 mov eax,dword ptr [hProc]
004118B3 push eax
004118B4 call dword ptr[__imp__TerminateProcess#8(4181E4h)]
004118BA cmp esi,esp
esi returned zero. why ?
What is VDLL2_API defined as? It may be interfering with the calling convention (which is meant to be WINAPI for this function, as you write it later on the same line).
Stack problems on exit (ESI, ESP) usually indicate that you have your calling conventions mixed up. You appear to have used FARPROC consistently everywhere else, but since you know the exact prototype of the function, try typedef-ing that as the type to use instead:
typedef BOOL (WINAPI *TERMINATEPROCESS_PROC)(HANDLE, UINT);
Now use TERMINATEPROCESS_PROC everywhere instead of FARPROC.
Don't write this kind of code yourself. Use the Detours library from Microsoft Research.