Valhalla Legends Archive

Programming => General Programming => Assembly Language (any cpu) => Topic started by: iago on July 12, 2003, 07:09 AM

Title: I'm having a problem using CheckRevision
Post by: iago on July 12, 2003, 07:09 AM
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:
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;
   }
}


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
Title: Re:I'm having a problem using CheckRevision
Post by: Yoni on July 12, 2003, 10:07 AM
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:
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;
}


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.
Title: Re:I'm having a problem using CheckRevision
Post by: K on July 12, 2003, 12:42 PM
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:



// .....
// .....
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);
}
Title: Re:I'm having a problem using CheckRevision
Post by: iago on July 12, 2003, 06:37 PM
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?
Title: Re:I'm having a problem using CheckRevision
Post by: Adron on July 12, 2003, 08:47 PM
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:



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;
}


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.
Title: Re:I'm having a problem using CheckRevision
Post by: iago on July 12, 2003, 09:37 PM
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 :)
Title: Re:I'm having a problem using CheckRevision
Post by: Arta on July 13, 2003, 01:37 PM
First, EEEWWWW+++ at giving away answer ::)

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


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;
}



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);
}
Title: Re:I'm having a problem using CheckRevision
Post by: iago on July 13, 2003, 04:20 PM
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 :-)
Title: Re:I'm having a problem using CheckRevision
Post by: K on July 13, 2003, 06:13 PM
Good idea, because my code is very poorly written.  ;D
Title: Adron: another problem
Post by: Kp on July 14, 2003, 01:52 PM
Quote from: Adron on July 12, 2003, 08:47 PM
That's the one problem with using Blizzards dll to do the check.
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).
Title: Re:Adron: another problem
Post by: iago on July 14, 2003, 03:06 PM
Quote from: Kp on July 14, 2003, 01:52 PM
Quote from: Adron on July 12, 2003, 08:47 PM
That's the one problem with using Blizzards dll to do the check.
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).

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
Title: Re:I'm having a problem using CheckRevision
Post by: iago on July 15, 2003, 08:47 AM
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 :)
Title: Re:I'm having a problem using CheckRevision
Post by: Arta on July 16, 2003, 02:19 PM
Yeah, I was reversing CheckRevision last week. Was fun++ :)