Page 1 of 3

C++ to PB. Headaches, white nights, etc..

Posted: Mon Jul 10, 2006 1:47 pm
by Inf0Byt3
Hi! I found this code that help creating global API hooks without entering ring0 with a vxd and it seems pretty cool. Unfortunately it is in C++ and I can't manage to translate it :(. Any help is much appreciated. It has 2 parts: an injector (app) and a dll. The code is not big (~4 kb each).

Oh, and what does "->" means in C++? I can't find any replacement in PB...

The injector

Code: Select all

#include <windows>
#include <stdlib>
#include <conio>

int DoHook(int pid, bool UnHook, HMODULE hFreeModule)
{

	HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, // Specifies all possible access flags
									FALSE, 
									pid);
	if (hProcess == NULL) 
		return 0;

	char szLibFile[MAX_PATH] = "C:\\work\\vc6\\SharedModule\\Debug\\sharedmodule.dll";
 
	int cch = 1 + strlen(szLibFile);

	PSTR pszLibFileRemote = (PSTR)::VirtualAllocEx(hProcess, NULL, cch, MEM_COMMIT, PAGE_READWRITE);

	if (pszLibFileRemote == NULL) 
	{
		printf("pszLibFileRemote was NULL");
		return 0;
	}

	if (!::WriteProcessMemory(hProcess, (PVOID)pszLibFileRemote, (PVOID)szLibFile, cch, NULL))
	{
		printf("\nWriteProcessMemory Failed");
		return 0;
	}

	PTHREAD_START_ROUTINE pfnThreadRtn = NULL;

	if(UnHook)
		pfnThreadRtn = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle("Kernel32"), "FreeLibrary");
	else
		pfnThreadRtn = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle("Kernel32"), "LoadLibraryA");

	if (pfnThreadRtn == NULL) 
	{
		printf("\nGetProcAddress Failed");
		return 0;
	}
 
	HANDLE hThread;
 
	if(UnHook)
		hThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, (HMODULE)hFreeModule, 0, NULL);
	else
		hThread = ::CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, (PVOID)pszLibFileRemote, 0, NULL);

	if (hThread == NULL) 
	{
		printf("\nCreateRemoteThread Failed");
		return 0;
	}

	::WaitForSingleObject(hThread, INFINITE);

	if (pszLibFileRemote != NULL) 
	  ::VirtualFreeEx(hProcess, (PVOID)pszLibFileRemote, 0, MEM_RELEASE);

	if (hThread  != NULL) 
		::CloseHandle(hThread);

	if (hProcess != NULL) 
		::CloseHandle(hProcess);

	return 1;
}

// We will require this function to get a module handle of our
// original module

HMODULE EnumModules(int pid, char szLibFile[MAX_PATH])
{
	HMODULE hMods[1024];
	DWORD cbNeeded;

	unsigned int i;

	HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, // Specifies all possible access flags
									FALSE, 
									pid);

	if (hProcess == NULL) 
		return 0;

    HMODULE m_hModPSAPI = ::LoadLibraryA("PSAPI.DLL");

	typedef BOOL (WINAPI * PFNENUMPROCESSMODULES)
	(
		HANDLE hProcess,
		HMODULE *lphModule,
		DWORD cb,
		LPDWORD lpcbNeeded
	);

	typedef DWORD (WINAPI * PFNGETMODULEFILENAMEEXA)
	(
		HANDLE hProcess,
		HMODULE hModule,
		LPSTR lpFilename,
		DWORD nSize
	);

    PFNENUMPROCESSMODULES   m_pfnEnumProcessModules;
    PFNGETMODULEFILENAMEEXA m_pfnGetModuleFileNameExA;

	m_pfnEnumProcessModules = (PFNENUMPROCESSMODULES)::GetProcAddress(m_hModPSAPI, "EnumProcessModules");

	m_pfnGetModuleFileNameExA = (PFNGETMODULEFILENAMEEXA)::GetProcAddress(m_hModPSAPI, "GetModuleFileNameExA");

	if( m_pfnEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
	{
		for ( i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
		{
			char szModName[MAX_PATH];

			// Get the full path to the module's file.

			if ( m_pfnGetModuleFileNameExA( hProcess, hMods[i], szModName, sizeof(szModName)))
			{
				// Print the module name and handle value.

				printf("\t%s (0x%08X)\n", szModName, hMods[i] );

				if(strcmp(szModName, szLibFile) == 0)
				{
					::FreeLibrary(m_hModPSAPI);

					return hMods[i];
				}
			}
		}
	}

	if (hProcess != NULL) 
	::CloseHandle(hProcess);

	return 0;
}

int main(int argc, char* argv[])
{
	int pid = atol(argv[1]);
	HMODULE hModule; 

	DoHook(pid, false, 0);

	hModule = EnumModules(pid,"C:\\work\\vc6\\SharedModule\\Debug\\sharedmodule.dll");

	getch();

	if(0 != hModule)
		DoHook(pid, true, hModule);

	printf("\n");

	EnumModules(pid,"C:\\Parag\\pidwatcher\\Debug\\sharedmodule.dll");

	return 0;
}
DLL module:

Code: Select all

#include <stdio>
#include <imagehlp>
#include <stdlib>

HANDLE g_hModule = INVALID_HANDLE_VALUE;
PROC g_OriginalCopyFileW;

typedef BOOL WINAPI MyCopyFileW_t
(
	LPCWSTR lpExistingFileName,
	LPCWSTR lpNewFileName,
	BOOL bFailIfExists
);

BOOL WINAPI MyCopyFileW(LPCWSTR lpExistingFileName,	LPCWSTR lpNewFileName, BOOL bFailIfExists)
{
	BOOL ReturnValue;
	
	MyCopyFileW_t* fn = (MyCopyFileW_t*)g_OriginalCopyFileW;
	
	ReturnValue = (*fn)(lpExistingFileName, lpNewFileName, bFailIfExists);

	return ReturnValue;
}

void SetHook(HMODULE hModuleOfCaller, LPSTR LibraryName, PROC OldFunctionPointer, PROC NewFunctionPointer)
{
	if(hModuleOfCaller == g_hModule)
		return;
	if(hModuleOfCaller == 0)
		return;

	ULONG ulSize;

	// Get the address of the module’s import section
	PIMAGE_IMPORT_DESCRIPTOR pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData
	(
		hModuleOfCaller, 
		TRUE, 
		IMAGE_DIRECTORY_ENTRY_IMPORT, 
		&ulSize
	);

	// Does this module have an import section ?
	if (pImportDesc == NULL)
		return;

	// Loop through all descriptors and find the 
	// import descriptor containing references to callee’s functions
	while (pImportDesc->Name)
	{
		PSTR pszModName = (PSTR)((PBYTE) hModuleOfCaller + pImportDesc->Name);
		
		if (stricmp(pszModName, LibraryName) == 0) 
			break; // Found

		pImportDesc++;
	} // while

	if (pImportDesc->Name == 0)
		return;

	//Get caller’s IAT 
	PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)( (PBYTE) hModuleOfCaller + pImportDesc->FirstThunk );

	PROC pfnCurrent = OldFunctionPointer;

	// Replace current function address with new one
	while (pThunk->u1.Function)
	{
		// Get the address of the function address
		PROC* ppfn = (PROC*) &pThunk->u1.Function;
		// Is this the function we’re looking for?
		BOOL bFound = (*ppfn == pfnCurrent);

		if (bFound) 
		{
			MEMORY_BASIC_INFORMATION mbi;
			
			::VirtualQuery(ppfn, &mbi, sizeof(MEMORY_BASIC_INFORMATION));

			// In order to provide writable access to this part of the 
			// memory we need to change the memory protection

			if (FALSE == ::VirtualProtect(mbi.BaseAddress,mbi.RegionSize,PAGE_READWRITE,&mbi.Protect))
				return;

			*ppfn = *NewFunctionPointer;

			BOOL bResult = TRUE;

			// Restore the protection back
			DWORD dwOldProtect;

			::VirtualProtect(mbi.BaseAddress,mbi.RegionSize,mbi.Protect,&dwOldProtect);
			
			break;
		} // if

		pThunk++;

	} // while
}

PROC EnumAndSetHooks(LPSTR BaseLibraryName, LPSTR BaseFunctionName, PROC NewFunctionPointer, bool UnHook, PROC Custom)
{
	HMODULE hMods[1024];
	DWORD cbNeeded;
	unsigned int i;
	typedef BOOL (WINAPI * PFNENUMPROCESSMODULES)
	(
		HANDLE hProcess,
		HMODULE *lphModule,
		DWORD cb,
		LPDWORD lpcbNeeded
	);

	HMODULE hBaseLib = LoadLibrary(BaseLibraryName);

	PROC hBaseProc;

	if(UnHook)
		hBaseProc = (PROC) Custom;
	else
		hBaseProc = GetProcAddress(hBaseLib, BaseFunctionName);

	PFNENUMPROCESSMODULES m_pfnEnumProcessModules;
	HMODULE m_hModPSAPI = ::LoadLibraryA("PSAPI.DLL");

	m_pfnEnumProcessModules = (PFNENUMPROCESSMODULES)::GetProcAddress(m_hModPSAPI, "EnumProcessModules");

	HANDLE hProcess = ::GetCurrentProcess();

	if( m_pfnEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
	{
		for ( i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
		{
			SetHook(hMods[i], BaseLibraryName, hBaseProc, NewFunctionPointer); 
		}
	}

	return hBaseProc;
}

BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
	switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH:
			g_hModule = hModule;
			
			g_OriginalCopyFileW = EnumAndSetHooks("KERNEL32.DLL", "CopyFileW", (PROC) MyCopyFileW, false, 0);
				
			break;
		case DLL_PROCESS_DETACH:
			EnumAndSetHooks("KERNEL32.DLL", "CopyFileW", (PROC) GetProcAddress(LoadLibrary("KERNEL32"),"CopyFileW"), true, (PROC) MyCopyFileW);
			break;
	}

	return TRUE;
}

Posted: Mon Jul 10, 2006 1:55 pm
by dracflamloc
-> is similar to the \ in purebasic for structures. However it won't have the same effect because in C++ the -> can be a reference from a pointer (get it, it looks like an arrow) to a function call, not just normal data types.

PB Simplifies it a bit. In Pb, structures no matter how they are defined:

*src.MYSTRUC = alocatememory(sizeof(MYSTRUC))
src2.MYSTRUC

Both of these can have thier member fields access by

*src\x=3
src2\x=3

In C/C++ you would have to use -> for the top version and . for the bottom.


(Though it seems there aren't any classes/objects in this code so it should be an easy conversion)

Posted: Mon Jul 10, 2006 2:02 pm
by Inf0Byt3
Thanks. I had a hunch, but wasn't shure about it...

[Edit]
Oh, i see... Hmm, what about compiling this with VC2005 Express and than including it in a lib? Would it be hard?

Posted: Mon Jul 10, 2006 2:19 pm
by dracflamloc
Not sure I haven't really messed with PB4 yet. Still waiting on the nix version

Posted: Mon Jul 10, 2006 2:24 pm
by Inf0Byt3
Oh :D. I didn't have any problems until now, and I hope I'll never have :). But a bugfix version would be cool (one with SendNetworkFile with callback and buffered transfer :D).

For now I'll wait until VC++ completes (just started downloading it) and try to make an object out of the code. I hope this will work.

Posted: Mon Jul 10, 2006 7:32 pm
by KarLKoX
Click Me: not tested (my antivirus always block the app and i don't want to deactivate it ^_^).

Posted: Mon Jul 10, 2006 7:54 pm
by Inf0Byt3
Wow that's amazing! Thank you very much! I will now see how it works and make some tests.

Posted: Mon Jul 10, 2006 9:22 pm
by Inf0Byt3
Hmm, this is strange, I was trying to use it but it seems not to work here. Can you please try to make an example (hook messageboxa for example)? I used 'explorer.exe' as programparameter. it enumerates its modules and after that it quits...

Posted: Mon Jul 10, 2006 10:46 pm
by KarLKoX
Did you try the original code to compare with the PB code ? Perhaps the original code do nothing too :?:

Posted: Mon Jul 10, 2006 11:44 pm
by Inf0Byt3
You're right... Here is the original page with the code. I'll try to make it work.

http://www.codeproject.com/system/api_m ... eashed.asp

Posted: Tue Jul 11, 2006 7:27 pm
by Henrik
@Inf0Byt3 here is another article about it
API monitoring unleashed - I to IV
Starts at the bottom of this page:
http://www.itvidya.com/article/650

Posted: Tue Jul 11, 2006 8:30 pm
by Inf0Byt3
Thanks. It's allmost like like the article I found :D.

Posted: Wed Jul 12, 2006 4:39 pm
by Henrik
Inf0Byt3 wrote:Thanks. It's allmost like like the article I found :D.
the code is the same but the article is in greater detail, if i rember correct. hmm, i think it's is :roll:

Annyway
best Henrik

Posted: Wed Jul 12, 2006 5:06 pm
by Inf0Byt3
It's good. I allmost made it... When it is done, I will make a lib or an include out of it.

Posted: Wed Jul 12, 2006 5:12 pm
by Henrik
Cool Infobyt 8)
Did you compile it with VC2005 Express ?