• Welcome to Valhalla Legends Archive.
 

I'm having a problem using CheckRevision

Started by iago, July 12, 2003, 07:09 AM

Previous topic - Next topic

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:
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
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Yoni

#1
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.

K

#2
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);
}

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?
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


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:



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.

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 :)
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Arta

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

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 :-)
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


K

Good idea, because my code is very poorly written.  ;D

Kp

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).
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

iago

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
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


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 :)
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Arta

Yeah, I was reversing CheckRevision last week. Was fun++ :)