Valhalla Legends Forums Archive | Assembly Language (any cpu) | I'm having a problem using CheckRevision

AuthorMessageTime
iago
Ok, I'll admit this isn't the best way to do this, but for now it's the easiest way I could do this.

Anyway, I am using this member function to calculate VersionHash and Checksum:
[code]BOOL BNetHashing::GetVersionInfo(const char *StormPath, const char *BattlePath, const char *StarcraftPath, HMODULE IX86Filename, const char *ChecksumFormula, char *BufferForExeInfo, DWORD *VersionHash, DWORD *CheckSum)
{
   BOOL CheckRevisionSuccess = false;
   FARPROC CheckRevision = GetProcAddress(IX86Filename, "CheckRevision");

   *CheckSum = 0;
   *VersionHash = 0;
   if(CheckRevision)
   {
      __asm
      {
         push BufferForExeInfo
         push CheckSum
         push VersionHash
         push ChecksumFormula
         push BattlePath
         push StormPath
         push StarcraftPath

         call CheckRevision
         mov CheckRevisionSuccess, eax
      }
      return CheckRevisionSuccess;
   }
   else
   {
      cout << "Your IX86Version Check file is invalid!" << endl;
      return false;
   }
}[/code]

My problem is, I run this in two different programs with the same IX86 dll file and the same paths, and the same ChecksumFormula, I get different values returned.

I have a feeling I'm overlooking something, perhaps one of those should be a structure instead of a dword, or maybe one of the registers have to set before calling this function that I missed..?

If anybody has any experience with this function, please let me know!

Thanks!
-iago
July 12, 2003, 12:09 PM
Yoni
You really don't need to use inline ASM to call a function that was returned from GetProcAddress. You can accomplish this with a typedef.
(Edit: You can also do it without inline ASM and without a typedef, but that's really icky.)

This should be more or less equivalent to your code:
[code]typedef BOOL (__stdcall *CheckRevisionProc)(const char *ExePath, const char *DllPath, const char *SnpPath, const char *Formula, DWORD *VersionHash, DWORD *Checksum, char *ExeInfo);

BOOL BNetHashing::GetVersionInfo(const char *StormPath, const char *BattlePath, const char *StarcraftPath, HMODULE IX86Filename, const char *ChecksumFormula, char *BufferForExeInfo, DWORD *VersionHash, DWORD *CheckSum)
{
BOOL CheckRevisionSuccess = false;
CheckRevisionProc CheckRevision = (CheckRevisionProc)GetProcAddress(IX86Filename, "CheckRevision");

*CheckSum = 0;
*VersionHash = 0;
if(CheckRevision)
CheckRevisionSuccess = CheckRevision(StarcraftPath, StormPath, BattlePath, ChecksumFormula, VersionHash, CheckSum, BufferForExeInfo);
else
cout << "Your IX86Version Check file is invalid!" << endl;

return CheckRevisionSuccess;
}[/code]

As for why it's failing... It could be some compiler optimization thing that maybe messed up your inline ASM, but I doubt it. Try doing it without inline ASM and see if it works better.
July 12, 2003, 3:07 PM
K
It's because CheckRevision calls GetModuleFileName() instead of using your executable parameter. You need to patch the call. There are several different ways to do that (walk the import table, etc). This is the way I did it, which is pretty much the same as the way Adron did it (albiet with less error checking :P) in the nbbot source floating around:

[code]

// .....
// .....
CheckRevision = (pfCheckRevision)GetProcAddress(hVers[i], "CheckRevision");
      
if (!bPatched)
{
   // align loop variable on word boundry
   DWORD *lpdwTmp = (DWORD*)((DWORD)CheckRevision & ~0x03);
   DWORD dwGMF = (DWORD)GetModuleFileName;

   // this should be fixed so as
   // not to loop forever if it's not found.
   while( *++lpdwTmp != dwGMF);
   *lpdwTmp = (DWORD)MyGetModuleFileName;
   bPatched = true;
}

// .....
// .....

DWORD __stdcall MyGetModuleFileName(HMODULE hMod, LPSTR lpszBuff, DWORD dwOpt)
{
   // may not want to hardcode this.
   char const *szFile = "C:\\program files\\starcraft\\starcraft.exe";
   const DWORD dwLen = (DWORD)strlen(szFile);

   if (hMod == GetModuleHandle(NULL))
   {
      if (sizeof(lpszBuff) < dwLen)
         return 0;

      strcpy(lpszBuff, szFile);
      return dwLen;
   }
   else
      return GetModuleFileName(hMod, lpszBuff, dwOpt);
}[/code]
July 12, 2003, 5:42 PM
iago
Yoni - I knew that I could use a typedef, but I never knew the correct syntax for them until a couple days ago, so I've avoided them by using inline assembly. Thanks, though :P

K - So what you're saying is that when I pass it "starcraft.exe" it isn't using it at all, instead it's getting the checksum of storm.dll, battle.snp, and my program?
July 12, 2003, 11:37 PM
Adron
It does indeed use GetModuleHandle(0) instead of your exe file. That's the one problem with using Blizzards dll to do the check.

And to do it without typedefs or asm, something like:

[code]

BOOL BNetHashing::GetVersionInfo(const char *StormPath, const char *BattlePath, const char *StarcraftPath, HMODULE IX86Filename, const char *ChecksumFormula, char *BufferForExeInfo, DWORD *VersionHash, DWORD *CheckSum)
{
BOOL CheckRevisionSuccess = false;
FARPROC CheckRevision = GetProcAddress(IX86Filename, "CheckRevision");

*CheckSum = 0;
*VersionHash = 0;
if(CheckRevision)
CheckRevisionSuccess = ((BOOL (__stdcall *)(const char *, const char *, const char *, const char *, DWORD *, DWORD *, char *))CheckRevision)(StarcraftPath, StormPath, BattlePath, ChecksumFormula, VersionHash, CheckSum, BufferForExeInfo);
else
cout << "Your IX86Version Check file is invalid!" << endl;

return CheckRevisionSuccess;
}
[/code]

Typedef doesn't really have anything to do with this, all you have to do is cast the function pointer to the right type. In general typedef's can be used to make casts look better, but they're not necessary.
July 13, 2003, 1:47 AM
iago
Ok, I'll solve that problem then. Thanks! I know I've seen GetModuleHandle(0) in the code before, but I thought it was in battle.snp before calling the CheckRevision function.. guess my memory isn't as good as it used to be :-)

Ps. I guess this doesn't really belong on the asm forum, since that's not really where the problem was.. feel free to move it, if you want.. I don't like posting in botdev, though, since there's too much garbage there :)
July 13, 2003, 2:37 AM
Arta
First, EEEWWWW+++ at giving away answer ::)

Second, you may find this useful, for this problem and others:

[code]
bool CProcess::PatchIAT(DWORD ImageBase, DWORD Find, DWORD Replace){
   // Get ImageBase address
   if(!ImageBase){
      return false;
   }

   IMAGE_DOS_HEADER *DosHeaders = (IMAGE_DOS_HEADER*)ImageBase;
   IMAGE_NT_HEADERS *Header = (IMAGE_NT_HEADERS*)(ImageBase+DosHeaders->e_lfanew);
   
   // Get an address for the IAT
   DWORD IATSize = Header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;
   DWORD IAT = ImageBase+Header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress;
   
   // Search for Find and overwrite it with Replace
   for(int i=IAT; i<=IAT+IATSize; i+=4){
      if(*(DWORD*)i == Find){
         DWORD Old;
         if(!VirtualProtect((LPVOID)i, 4, PAGE_READWRITE, &Old)){
            return false;
         }
         *(DWORD*)i = Replace;
         return true;
      }
   }

   return false;
}
[/code]

[code]
HINSTANCE hVersionDLL = LoadLibrary(DllFilename);

...

// Patch checkrevision
if(!Process.PatchIAT((DWORD)hVersionDLL, (DWORD)&GetModuleHandleA, (DWORD)&MyGetModuleHandleA)){
   Print(RED, "Unable to patch %s! Attempting to connect with unpatched file...\n", DllFilename);
}
[/code]
July 13, 2003, 6:37 PM
iago
Arta - The only part of his answer I'm using is the part that I repeated.. I'm going to write my own code for it when I get around to doing some more work, because that's the way I am :-)
July 13, 2003, 9:20 PM
K
Good idea, because my code is very poorly written. ;D
July 13, 2003, 11:13 PM
Kp
[quote author=Adron link=board=7;threadid=1882;start=0#msg14626 date=1058060868]
That's the one problem with using Blizzards dll to do the check.[/quote]You forgot to mention that it leaks memory. :) He'll need to implement fixes for that too (probably using IAT patches to catch all the allocations/deallocations).
July 14, 2003, 6:52 PM
iago
[quote author=Kp link=board=7;threadid=1882;start=0#msg14806 date=1058208738]
[quote author=Adron link=board=7;threadid=1882;start=0#msg14626 date=1058060868]
That's the one problem with using Blizzards dll to do the check.[/quote]You forgot to mention that it leaks memory. :) He'll need to implement fixes for that too (probably using IAT patches to catch all the allocations/deallocations).
[/quote]

I was going to point that out :-P

My plan is, once I get it working I'll work on reversing the .dll and finding out how they work so I can write my own 1337 codez :P
July 14, 2003, 8:06 PM
iago
Just FYI, I got it working. I did it a different way than was suggested, but thanks for the answer anyway, know that it was GetModuleHandleA() that was causing the problem helped a lot :)
July 15, 2003, 1:47 PM
Arta
Yeah, I was reversing CheckRevision last week. Was fun++ :)
July 16, 2003, 7:19 PM

Search