Comparing DLL's on file with in-memory

Started by
12 comments, last by Extrarius 15 years, 5 months ago
I'm trying to compare certain DLL's in memory with their physical bytes on file. What I'm doing is this..

HMODULE hMemMod = (HMODULE)g_moduleList.at(z).module;
if (IsConcernedModule(hMemMod))
{
	char pFileName[260];
	if (GetModuleFileNameExA(GetCurrentProcess(),hMemMod,pFileName,_MAX_PATH) > 0)
	{
		FILE* fpPhysicalModule;
		char szModuleName [ MAX_PATH ]; ( * szModuleName ) = 0;
		long lSize;
		char* pbPhysModule;
		size_t numBytes;

		fpPhysicalModule = fopen(pFileName,"rb");
		if (!fpPhysicalModule)
		{
			return;
		}

		fseek(fpPhysicalModule, 0, SEEK_END);
		lSize = ftell(fpPhysicalModule);
		rewind(fpPhysicalModule);

		pbPhysModule = (char*)malloc(sizeof(char)*lSize);
		numBytes = fread(pbPhysModule, 1, lSize,fpPhysicalModule);
		fclose(fpPhysicalModule);

		GetModuleBaseNameA(GetCurrentProcess(),(HMODULE)g_moduleList.at(z).module,szModuleName,sizeof(szModuleName));
		DWORD dwMemModule = (DWORD)GetModuleHandleA(szModuleName);

		BYTE* moduleAddress = (BYTE*)dwMemModule;
		BYTE* physicalAddress = (BYTE*)pbPhysModule;

		for (int i = 0;i < lSize;i++)
		{
			if (moduleAddress != physicalAddress)
			{
				// this gets called all the time, even if i'm not manipulating the module in memory!
				g_intInsecurity.push_back(i);
			}
		}
				
	}
}
the problem.. Even if I don't manipulate anything in memory, the address at in memory compared to the address at on file is always different. I know I have to be doing something wrong syntax wise. Any help would be greatly appreciated.
Advertisement
Does it happen literally for every single byte? Because there's a ton of stuff that's within the PE (EXE/DLL) file space once it gets loaded into memory that will be different:

- Values of global/static variables (these change during the normal course of execution)

- Values of the placeholders in the import address table (these change during load time)

- Any other non-relative addresses that are remapped (possibly switch tables) (these should change during load time)

- Maybe some other stuff; I haven't analyzed DLLs as much as EXEs.
Assuming this is for some sort of hacking protection, you may be better comparing just the code segments of the DLL - although I'm not sure if that could change during the load process too. For details of that, you'd want to look into the PE File Format (There may be better sources elsewhere though).
Actually I went and logged it, and here's what I got.
				for (int i = 0;i < lSize;i++)				{					if (moduleAddress != physicalAddress)					{						writelog("%s : Offset 0x%x Physical: 0x%x Memory: 0x%x\n",szModuleName,i,physicalAddress,moduleAddress);						//g_intInsecurity.push_back(i);					}					else					{						writelog("%s : Offset 0x%x Match 0x%x\n",szModuleName,i,physicalAddress);					}				}


And the output log...
http://www.di-labs.com/memorycompare_example.txt
Offset in DLL file is different from virtual address. Basically a PE file (which includes DLLs) consists of sections, each section loads at different address and that information can be found in the file header. Here's some information about PE file format.
I don't like the name std::vector. I'd be happy if it was std::array.
From what I've been reading alignment in the virtual addresses, and the alignment of the offsets on file differ. Now does anyone have any links for tutorials or research papers on how to properly align PE files and PE in loaded memory, in order to gain a good comparison?
You're going to have to write a PE module parser, because DLLs have relocation sections which modify the code depending on where it is loaded, and even then you can only compare the memory segment.

Honestly, if you just want to make sure the file hasn't been modified, you're better off using some kind of machine code obfuscator. It's trivial to reverse engineer the kind of check you're trying to write and make it refer to some other file (like the original dll renamed to "original.dll.org") instead of the file you want it to refer to.

You can't have very good anti-hacker "security" at all in software - it simply isn't possible to thwart talented reverse engineers, and anybody that does reverse engineering is going to be talented because it's not something that everyday people do. The closest thing to an amateur reverse engineer is a student doing something for class, but they're not going to hacking your program anyways so you don't need to worry about them.

If you still insist on doing basic checks for whatever reason, then you absolutely must learn how DLLs are loaded and processed by the system, and how reverse engineering and debugging is done. Two starting places: What Goes On Inside Windows 2000: Solving the Mysteries of the Loader; Windows Anti-Debug Reference.

Another simple trick is using the process and thread permission system implemented in windows - the common trick (by cheaters far more than by reverse engineers) of using WriteProcessMemory can be somewhat circumvented by having the process revoke all permissions to it's token at the very start of the program, which can make it difficult for the cheater to get it's process permission to open the process with write priveleges. In order to take advantage of that, though, you'll need to have the main executable launch a copy of itself using CreateProcess and pass the "CREATE_BREAKAWAY_FROM_JOB | DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP" with the appropriate permissions. Another simple way is to make a number class that stores important numeric values in two separate variables. For example, for a 32-bit int, you'd store it as one 32-bit int that is a random number and then all accesses to the value would be based on the random number XOR an appropriate value to get the final value. That way, searching memory for a specific number will never find it, and actual reverse engineering is required.

[Edited by - Extrarius on November 25, 2008 11:25:03 AM]
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
Points to Extrarious for the link to the loader article! (That's the first thing I thought of when I saw the thread title). Points to muse1987 as well. Pietrek owns spelunking the PE File.

There's more to be gleaned via wikipedia: Portable Executable. There are few links here that aren't there. There's info about debugging info here. There are additional links here.

"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
Let's not forget that Windows is going to dynamically rebase DLLs as necessary, plus Vista may apply ASLR to the thing. That's going to alter all sorts of addresses, even within the code segment.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Quote:Original post by Promit
Let's not forget that Windows is going to dynamically rebase DLLs as necessary, plus Vista may apply ASLR to the thing. That's going to alter all sorts of addresses, even within the code segment.
Is it? Surely only the jump table for DLL imports will be patched, and I didn't think that was in the code segment (Or if it is, it's probably possible to find the address of it and ignore it).

This topic is closed to new replies.

Advertisement