cAddressTable

Posts 15 of 5 · Page 1 of 1
cAddressTable
Under MIT Licensee

If there are any tutorials someone wants me to write, please notify me about them. I am open to all ideas, as long as they're not towards specific games. As my computer isn't much of a gaming computer and developing hacks for any game would take years on this piece of crap.

Because I just wrote a huge ass tutorial on cBreakpoint(which no one read), I'm not doing much for this one. The methods are pretty self explanatory. I'll write on it in an hour or so..

cAddressTable is a class that enables you to search the IAT, and EAT for exports and imports, or replace them. This hasn't undergone any extensive testing, and if the PE Header of the targeted module is wiped at runtime, this class will not work. Unless you're willing to manually set the table's Import\Export table addresses. This will also not work if the application is encrypted or packed. Unless, like said, you define base addresses yourself.

Defining Base Addresses yourself
There are times when your target will completely wipe the PE header, which will prevent cAddressTable::GetAddressTable from returning valid data. Thus you will be required to locate the IAT or EAT manually. There are several REing techniques, and if your target is encrypted or packed, the unpacking stub will have to manage the imports and setting up the IAT itself. Even when the target has been unpacked by the unpacking stub, there is a high chance your target's code, or the unpacking stub will clear the PE header, and thus searching for the IAT using the PE header proves rather difficult. What you can do, is setup the AddressTable struct manually. You do this as done below :

[php]
AddressTable* adrTable = new AddressTable();
adrTable->moduleBase = GetModuleHandle(0);
adrTable->tableOffset = OFFSET_FROM_MODULE_BASE_IAT;
adrTable->size = 25; //In bytes.
adrTable->type = IAT;
[/php]Then pass that struct pointer to SearchIATForAddress, or whichever method you wish to use. All those members should explain themselfs pretty well. tableOffset is the offset from the base, which when added to the base results in the IAT.
Searching for an IAT\EAT
If your target isn't encrypted, or doesn't have a damaged PE header, you're good to go, and you can simply use the method GetAddressTable. How to use the methods is defined below.


Public Methods
int SetTable(AddressTable* addrTable)
Sets the default address table. The first parameter is a pointer to the new default AddressTable. The data in this struct is copied to the class's local private member, m_addrTable.

Returns:
1 - Success
Else - Fail
unsigned long HookAddress(unsigned long tgtAddr, unsigned long writeAddr, ATHook* hookData)
Replaces a DWORD of the memory located at
the address defined in tgtAddr param with the memory defined in writeAddr param. hookData param takes a pointer to a ATHook struct. This function will set the passed struct accordingly. After this struct has been set by this function. It should NOT be altered before the calling of RestoreAddress

Returns:
1 - Success
Else - Fail
unsigned long SearchIATForAddress(unsigned long impAddress, AddressTable* adrTable = 0)
Searches the IAT for a defined address and returns where it's located in the IAT. This is not a relative address. The first param is the address to look for, the second in the address table to look in. If this param isn't given, it uses the default address table, set by SetTable.

Returns:
Absolute address where address is located in IAT - Success
0 - Fail


unsigned long SearchEATForAddress(char* expSymbolName, AddressTable* adrTable)

First param is the name of the exported symbol to look for, the second is the address table to look in. Returns either the absolute address where the export is located, or 0, which means it failed to locate it.

int RestoreAddress(ATHook* hookData);
Restores a breakpoint..

AddressTable* GetAddressTable(unsigned long module, short type);
Searches the PE header for the address table. Type can either be IAT, or EAT. Module must be a pointer to the modules base. Use GetModuelHandle to locate the base address of a module. Returns a pointer to a newly created, and set AddressTable struct, with all the members defined accordingly.
Source code.rarattachment deleted · 139 downloads before removal
Added a better doc on the class.
i read ur cBreakpoint tut, although i didnt get it, i like reading stuff
Very nice work, thanks for sharing! I've been looking for some existing code to use to obtain a list of exports from a target and couldn't find any simple and clean code to copy over into a project. I have imports done, but I wrote it many years ago and forgot the logic of how it works so I'd have to rewrite it all to understand it again.

This works out very nicely and has saved quite a bit of time. I was getting ready to just port Iczelion's Tutorial 7 from ASM to C++, but now I don't have to!

I also noticed a few things I did not know before. For example, the whole "DbgHelp" header, I was not aware of and have never used it before in my projects. It has some very useful functions, some of which I was coding by hand that should help greatly.

However, I noticed your code has a few logical errors and does not handle all exports correctly. Here is a small rewrite of the exports gathering code from a base address that should be correct and handle all types of exports (there are two!).

Code:
#include <windows.h>
#include <stdio.h>

#define MakePtr(cast, ptr, addValue) (cast)((DWORD)(ptr)+(DWORD)(addValue))

void GetAllExports(void * moduleBase)
{
	PIMAGE_DOS_HEADER dosHeader = 0;
	PIMAGE_NT_HEADERS peHeader = 0;
	IMAGE_DATA_DIRECTORY * dataDirectory = 0;
	DWORD dwModuleBase = 0;
	DWORD * ptrFuncs = 0;
	DWORD * ptrNames = 0;
	DWORD * funcIndexTable = 0;
	DWORD funcsSize = 0;
	DWORD namesSize = 0;
	_IMAGE_EXPORT_DIRECTORY * expDescBuf = 0;

	dwModuleBase = PtrToUlong(moduleBase);
	dosHeader = (PIMAGE_DOS_HEADER)moduleBase;
	peHeader = MakePtr(PIMAGE_NT_HEADERS, dosHeader, dosHeader->e_lfanew);
	dataDirectory = &peHeader->OptionalHeader.DataDirectory[0];
	expDescBuf = (_IMAGE_EXPORT_DIRECTORY*)(dataDirectory->VirtualAddress + dwModuleBase);
	ptrFuncs = (DWORD*)expDescBuf->AddressOfFunctions;
	ptrNames = (DWORD*)expDescBuf->AddressOfNames;
	funcIndexTable = (DWORD*)(expDescBuf->AddressOfNameOrdinals);
	ptrNames = (DWORD*)((DWORD)ptrNames + dwModuleBase);
	ptrFuncs = (DWORD*)((DWORD)ptrFuncs + dwModuleBase);
	funcIndexTable = (DWORD*)((DWORD)funcIndexTable + dwModuleBase);
	funcsSize = expDescBuf->NumberOfFunctions;
	namesSize = expDescBuf->NumberOfNames;
	
	// Not sure how this would happen, maybe corruption or intention?
	if(funcsSize != namesSize)
	{
		printf("[%s] WARNING: funcsSize(%i) != namesSize(%i)", funcsSize, namesSize);
	}

	// Loop through all of the named functions
	for(DWORD index = 0; index < namesSize; ++index)
	{
		DWORD ptrFuncAddr = 0;
		char * name = 0;
		unsigned long addr = 0;

		// Handle the funcsSize != namesSize case to prevent 
		// logic errors.
		if(index < funcsSize)
		{
			ptrFuncAddr = (unsigned long)ptrFuncs[index];
			addr = ptrFuncAddr + dwModuleBase;
		}

		name = (char*)(ptrNames[index] + dwModuleBase);

		// If this is true, the function is forwarded
		if( ptrFuncAddr >= dataDirectory->VirtualAddress && 
			ptrFuncAddr < dataDirectory->VirtualAddress + dataDirectory->Size)
		{
			char * forwardExport = (char * )UlongToPtr(addr);
			size_t len = strlen(forwardExport);
			char * moduleName = new char[len];
			char * moduleFunc = new char[len];
			memset(moduleName, 0, len);
			memset(moduleFunc, 0, len);
			for(size_t x = 0; x < len; ++x)
			{
				if(forwardExport[x] == '.')
				{
					memcpy(moduleName, forwardExport, x);
					memcpy(moduleFunc, forwardExport + x + 1, len - x - 1);
					break;
				}
			}
			HMODULE hNewDLL = GetModuleHandleA(moduleName);
			FARPROC fp = GetProcAddress(hNewDLL, moduleFunc);
			delete [] moduleName;
			delete [] moduleFunc;
			printf("* %s -> %s (%X)\n", name, UlongToPtr(addr), PtrToUlong(fp));
		}

		// Otherwise, a normal export, or something gone wrong if addr == 0
		else
		{
			printf("%s @ %X\n", name, addr);
		}
	}
}

int main(int argc, char * argv[])
{
	HMODULE hDLL = LoadLibraryA("FwdDLL.dll");
	if(hDLL == 0)
	{
		printf("Could not get a handle to the DLL.\n");
		return 0;
	}
	GetAllExports(hDLL);
	FreeLibrary(hDLL);
}
Most notably, your code does not handle 'Forwarded Exports', so that is something I added. Next, the address calculation code for your exported functions is not right either, it has to do with how you are using a WORD when a DWORD should be used instead for the funcIndexTable. You can open a DLL in Olly and check the output of your code that way as well, it's what I first did to notice the problem.

If you want to make your own DLL that forwards some exports, you can use the following simple code and def file and create an empty DLL project in Visual Studio and compile. If all works out well, you should be able to use Dependency Walker to verify the forward exported function as well as using my code to see them.

FwdDLL.cpp
Code:
extern "C" __declspec(dllexport) void Test1()
{
}
FwdDLL.def
Code:
LIBRARY FwdDLL
EXPORTS
	Test1
	Test2 = Kernel32.HeapAlloc
To link the DEF with the project (in case someone else reading this does not know how) simply go to Project->Properties->Configuration Properties->Linker->Input and type "FwdDLL.def" into the "Module Definition File" edit box. You should then be able to compile and load the DLL into Dependency Walker as previously mentioned.

Finally, here's an updated version of your code that should be correct. I did simple testing and it worked out well, but nothing too extensive, there might be other issues that have to be worked around, but this is just a start down to having a more flexible function:
Code:
unsigned long cAddressTable::SearchEATForAddress(char* expSymbolName, AddressTable* adrTable)
{
	AddressTable* selTable = (adrTable == 0 ? &m_addrTable : adrTable);

	DWORD* ptrFuncs;
	DWORD* ptrNames;
	DWORD*  funcIndexTable;

	DWORD funcsSize;
	DWORD namesSize;

	_IMAGE_EXPORT_DIRECTORY* expDescBuf = (_IMAGE_EXPORT_DIRECTORY*)(selTable->tableOffset + selTable->moduleBase);	
	ptrFuncs       = (DWORD*)expDescBuf->AddressOfFunctions;	
	ptrNames       = (DWORD*)expDescBuf->AddressOfNames;
	funcIndexTable = (DWORD*) expDescBuf->AddressOfNameOrdinals;

	ptrNames = (DWORD*)((DWORD)ptrNames + selTable->moduleBase);
	ptrFuncs = (DWORD*)((DWORD)ptrFuncs + selTable->moduleBase);
	funcIndexTable = (DWORD*)((DWORD)funcIndexTable + selTable->moduleBase);

	funcsSize = expDescBuf->NumberOfFunctions;
	namesSize = expDescBuf->NumberOfNames;

	for(DWORD i = 0; (i < namesSize && i < funcsSize); i++)
	{
		if(!strcmp(expSymbolName, (char*)(ptrNames[i] + selTable->moduleBase)))
		{
			if((unsigned long)ptrFuncs[i] >= adrTable->tableOffset && (unsigned long)ptrFuncs[i] <= adrTable->tableOffset + adrTable->size)
			{
				char * forwardExport = (char * )UlongToPtr(ptrFuncs[i] + selTable->moduleBase);
				size_t len = strlen(forwardExport);
				char * moduleName = new char[len];
				char * moduleFunc = new char[len];
				memset(moduleName, 0, len);
				memset(moduleFunc, 0, len);
				for(size_t x = 0; x < len; ++x)
				{
					if(forwardExport[x] == '.')
					{
						memcpy(moduleName, forwardExport, x);
						memcpy(moduleFunc, forwardExport + x + 1, len - x - 1);
						break;
					}
				}
				HMODULE hNewDLL = GetModuleHandleA(moduleName);
				FARPROC fp = GetProcAddress(hNewDLL, moduleFunc);
				delete [] moduleName;
				delete [] moduleFunc;
				return PtrToUlong(fp);
			}
			else
			{
				return ptrFuncs[i] + selTable->moduleBase;
			}
		}
	}
	return 0;
}
You should be able to run that on any function and check the address in OllyDbg and it should be correct! Thanks for sharing the original code!

[Edit] Noticed a small off by one bug:
Code:
if( ptrFuncAddr >= dataDirectory->VirtualAddress && ptrFuncAddr <= dataDirectory->VirtualAddress + dataDirectory->Size)
should be:
Code:
if( ptrFuncAddr >= dataDirectory->VirtualAddress && ptrFuncAddr < dataDirectory->VirtualAddress + dataDirectory->Size)
and has been fixed in the post.
Posts 15 of 5 · Page 1 of 1
This thread is closed for replies.

Tags for this Thread

Need help?