Eluding ActiveMark protection 


A 10-30 minutes method to remove the activemark protection from a game is presented here: 


AM=Activemark 

tools required : 
PTRW/W9x, SoftIce, C/C++ compiler, basic debugging skills. 

Now this method is very cumbersome, my english is bad and if your not familiar with S-ice and such 
you can skip all this :) 

Background: 

AM's Softice detection is quite simple. It tries to open a file like "\\.\SICE", "\\.\NTICE", etc and exits if success. So simply use Yoda's HOKO and you can play with SoftIce as you like. 
I needed PTRW 2000 / WinMe because it makes a correct dump, which I wasn't able (I didnt' try hard :) to make 
under NT/2k with Sice - addins. 


1). Method of finding our entrypoint: 
* under nt/2k, launch hoko (use CreateFileA hook and ret -1 if "\\.\NTICE" on CreateFileA) 
* launch the AM protected game, wait 1-3 seconds, press ctrl-d, then search for the following pattern in memory : 
if you cant find it, g and wait another second, then ctrl-d again. It is there, believe me. 

L0 lea edi, [esi + ...] 
L1 mov eax, [edi] 
L2 or eax, eax 
L3 jnz XXX 

i.e. s 400000 L -1 8B, 07, 09, C0, 74 

OK. note the above instruction, is something like lea edi, [esi + ...] 
because this will be our new entry point. 

now boot in w9x, load the .exe in PTRW, bpx at L0, and go. 
we will receive a break due to our bpx @ L0 

(Here I should tell you that even you make the perfect dump at this point, it won't work because: 
a) - the .exe already loaded &LoadLibraryA and &GetProcAddress somewhere in memory, making our crack OS-dependant); 
b) - you need to skip 2 more checks (2 JMPs); 
c) - the game is reading itself, so because our dump is different than the original exe, another error will occur. 

you will learn to avoid all these problems in a sec. 


for the point c). we will be loading at L0 a little DLL, am.dll, which will overwrite LoadLibraryA and GetProcAddress (at loadtime) in the game (their locations are found very easy : 
scroll down the code, you will see a call to [esi + ...] just a few lines below, notice the address on a 
paper, I call them LLA. The GPA (GetProcAddress) is just after the LLA. Also note the values of the ESI and EDI registers, as when the EIP will be "L1". (i.e LEA EDI, ... is executed) 
(ESI is always 401000, EDI is 401000 + some_value) 


so, we will write a little stub. Search down the code, you will notice that we have plenty of space (0s) just 
after this kind of jump, at L6... 
L4 POPAD 
L5 JMP ep 
L6 db 0, 0, 0, 0,... (lots of them, cant miss'em :) 

so, we'll jump at L6, make a call to loadlibrary, then jump back, then dump the exe. 

at L0: overwrite with : 
NOP 90 
JMP L6 ; (E9 XX XX XX XX) 


at L6: 
CALL $+7 ; (E8 07 00 00 00) 
db 'am.dll', 0 ; (7 bytes) 
mov edx, @LLA ; address of LoadLibraryA you've noted before 
call edx ; the stack is already with 'am.dll' on it 
; return to host 
pushad 
mov esi, 401000 ; (BE 00 10 40 00) (prev. noted value) 
mov edi, ... ; (BF xx xx xx xx) (prev. noted value) 
JMP L1 


ok, now is time to fix the point b). i.e. get rid of the subsequent AM checks. 

search in memory for the address of the following 
AS1 = "ActiveMark Client engine could not find a valid volume." 
AS2 = "Unable to start ActiveMark Client engine due to an internal error." 

ok, now search in memory for instructions : "PUSH AS1" and "PUSH AS2", (they appear only once) 
and look just before. Sometimes there is a simple JNZ or JZ instruction, sometimes it takes a 
little bit of effort but this is it : you just have to avoid (with a simple JMP) getting here. 
(shouldnt' take you more than 5 minutes of debugging). 


ok, now everything is set, just "pedump dump.exe", and go 
the game should not crash, if we did it right. 

Now, boot again in nt/w2k, make a quick tool that will scan dump.exe for "KERNEL32.DLL" (case sensitive) 
where we find a PE import section. (a routine is presented below) 

and fix the imports just before it... 

--------------------------------------------- 
Now, all we need is our injected DLL, "am.dll" 

the scope of this DLL is to check if the game tries to open itself, and present him with the 
original exe if so :). 

For this you could also use Yoda's HOKO. (great tool, too bad its for money) 


This am.dll presented here is configurable, meaning am_hooks.dll will have 4x2 bytes containing the 
addresses of LoadLibraryA and GetProcAddress in the game. Quick and DIRTY : 

With this, move the original game xxxx.exe into xxxx.ex_, copy the dumped.exe as xxxx.exe, 
compile & copy the am.dll into the game dir, fix the imports on the dumped.exe, edit am_hooks.bin 
and enter the addresses of LoadLibraryA and GetProcAddress, and there you go, launch the exe 
and it will go. No more AM. 

If something goes wrong, you will have to figure out for yourself 


--------------------------------------------------------------- 

// am.cpp : Defines the entry point for the DLL application. 
// 

#include 


typedef HANDLE WINAPI _LoadLibraryA_t 
( 
LPCTSTR lpLibraryName 
); 


typedef HANDLE WINAPI _GetProcAddress_t 
( 
HMODULE hModule, 
LPCTSTR lpFunctionName 
); 


typedef HANDLE WINAPI _CreateFile_t( 
LPSTR lpFileName, 
DWORD dwDesiredAccess, 
DWORD dwShareMode, 
LPSECURITY_ATTRIBUTES lpSecurityAttributes, 
DWORD dwCreationDisposition, 
DWORD dwFlagsAndAttributes, 
HANDLE hTemplateFile 
); 

static char g_szGame[MAX_PATH + 1]; 
static long g_szGameLen = 0; 
static char* g_szHooksPointersFile = "am_hooks.bin"; 


DWORD g_pfnCreateFile_ORIG = 0; 
DWORD g_pfnLoadLibraryA_ORIG = 0; 
DWORD g_pfnGetProcAddress_ORIG = 0; 

DWORD g_bLoadingKernel32 = FALSE; 


HANDLE WINAPI xCreateFile(LPSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); 
HANDLE WINAPI xLLA(LPCTSTR lpLibraryName); 
HANDLE WINAPI xGPA(HMODULE hModule, LPCTSTR lpFunctionName); 



void FixPointers() 
{ 

DWORD dwDummy; 
DWORD dwLLA = 0; 
DWORD dwGPA = 0; 


HANDLE hFile = CreateFile(g_szHooksPointersFile, 
GENERIC_READ, 
FILE_SHARE_READ, 
NULL, 
OPEN_EXISTING, 
FILE_ATTRIBUTE_NORMAL, 
NULL); 

if (INVALID_HANDLE_VALUE != hFile) 
{ 
ReadFile(hFile, &dwLLA, 4, &dwDummy, NULL); 
ReadFile(hFile, &dwGPA, 4, &dwDummy, NULL); 
CloseHandle(hFile); 

*((DWORD*)dwLLA) = (DWORD)xLLA; 
*((DWORD*)dwGPA) = (DWORD)xGPA; 

} 
} 


BOOL APIENTRY DllMain( HANDLE hModule, 
DWORD ul_reason_for_call, 
LPVOID lpReserved 
) 
{ 

switch (ul_reason_for_call) 
{ 
case DLL_PROCESS_ATTACH: 

// initialize the pointers 
g_pfnCreateFile_ORIG = (DWORD)CreateFileA; 
g_pfnLoadLibraryA_ORIG = (DWORD)LoadLibraryA; 
g_pfnGetProcAddress_ORIG = (DWORD)GetProcAddress; 
g_szGame[0] = '\0'; 

// Get self name 
g_szGameLen = GetModuleFileName(GetModuleHandle(NULL), g_szGame, MAX_PATH); 

// mark pointers in the game 

FixPointers(); 
break; 

case DLL_PROCESS_DETACH: 
break; 
} 

return TRUE; 
} 


HANDLE WINAPI xLLA(LPCTSTR lpLibraryName) 
{ 
long k, nLen; 
for (k = nLen = 0; !IsBadReadPtr(&lpLibraryName[k], 1) && lpLibraryName[k] != '\0'; k++) 
nLen++; 

if (nLen == 12) 
{ 
if (lpLibraryName[0] | 0x20 == 'k' && 
lpLibraryName[1] | 0x20 == 'e' && 
lpLibraryName[2] | 0x20 == 'r' && 
lpLibraryName[3] | 0x20 == 'n' && 
lpLibraryName[4] | 0x20 == 'e' && 
lpLibraryName[5] | 0x20 == 'l' && 
lpLibraryName[6] | 0x20 == '3' && 
lpLibraryName[7] | 0x20 == '2' && 
lpLibraryName[8] | 0x20 == '.' && 
lpLibraryName[9] | 0x20 == 'd' && 
lpLibraryName[10] | 0x20 == 'l' && 
lpLibraryName[11] | 0x20 == 'l') 
{ 
g_bLoadingKernel32 = 1; 
} 
else 
{ 
g_bLoadingKernel32 = 0; 
} 
} 

_LoadLibraryA_t* pfnMyLoadLibraryA = (_LoadLibraryA_t*)g_pfnLoadLibraryA_ORIG; 
return (*pfnMyLoadLibraryA)(lpLibraryName); 

} 

HANDLE WINAPI xGPA(HMODULE hModule, LPCTSTR lpFunctionName) 
{ 
if (g_bLoadingKernel32) 
{ 
long k, nLen; 
for (k = nLen = 0; !IsBadReadPtr(&lpFunctionName[k], 1) && lpFunctionName[k] != '\0'; k++) 
nLen++; 

if (11 == nLen) 
{ 
if ((lpFunctionName[0] | 0x20) == 'c' && 
(lpFunctionName[1] | 0x20) == 'r' && 
(lpFunctionName[2] | 0x20) == 'e' && 
(lpFunctionName[3] | 0x20) == 'a' && 
(lpFunctionName[4] | 0x20) == 't' && 
(lpFunctionName[5] | 0x20) == 'e' && 
(lpFunctionName[6] | 0x20) == 'f' && 
(lpFunctionName[7] | 0x20) == 'i' && 
(lpFunctionName[8] | 0x20) == 'l' && 
(lpFunctionName[9] | 0x20) == 'e' && 
(lpFunctionName[10] | 0x20) == 'a') 
{ 
return xCreateFile; 
} 
} 
} 

_GetProcAddress_t* pfnMyGetProcAddress = (_GetProcAddress_t*)g_pfnGetProcAddress_ORIG; 
return (*pfnMyGetProcAddress)(hModule, lpFunctionName); 
} 


HANDLE WINAPI xCreateFile(LPSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) 
{ 

if (IsBadReadPtr(lpFileName, 1)) 
return INVALID_HANDLE_VALUE; 

long k, nLen; 
for (k = nLen = 0; lpFileName[k] != '\0'; k++) 
nLen++; 

if (g_szGameLen == nLen) 
{ 
for (k = 0; k < nLen; k++) 
{ 
if ((lpFileName[k] | 0x20) != (g_szGame[k] | 0x20)) 
break; 
} 

if (k == nLen) 
{ 
lpFileName[k -1] = '_'; 
} 
} 

_CreateFile_t* pfnMyCreateFile = (_CreateFile_t*)g_pfnCreateFile_ORIG; 

return (*pfnMyCreateFile)(lpFileName, 
dwDesiredAccess, 
dwShareMode, 
lpSecurityAttributes, 
dwCreationDisposition, 
dwFlagsAndAttributes, 
hTemplateFile); 
} 
--------------------------------------------------------------- 


and the "optimised", DIRTY too, routine for fixing imports : 


bool FixImports(char* pszFileName) 
{ 
CString strOrigGame = CString(pszFileName); 
char* szFileName = (LPSTR)(LPCSTR)strOrigGame; 

HANDLE hFile = CreateFile(szFileName, 
GENERIC_READ, 
FILE_SHARE_READ, 
NULL, 
OPEN_EXISTING, 
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 
NULL); 

if (INVALID_HANDLE_VALUE == hFile) 
{ 
return false; 
} 

DWORD dwDummy; 
DWORD dwSize = GetFileSize(hFile, &dwDummy); 


HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, dwSize, "__KRNL32OFFS_SCAN2"); 
if (!hMap) 
{ 
printf("CreateFileMapping failed\n"); 
} 


DWORD* pMapMem = (DWORD*)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); 
ULONG _bFound = 0; 
ULONG _nOffset = 0; 
if (pMapMem) 
{ 
__asm 
{ 
cld 

mov _bFound, 0 

mov ecx, dwSize 
shr ecx, 2 
mov edi, pMapMem 

_loop: 
mov eax, 0x4e52454b // 'KERN' 
repnz scasd 
cmp ecx, 0 
jnz _found1 
jmp _notfound 

_found1: cmp [edi], 0x32334c45 // 'EL32' 
jz _found2 
jmp _notfound 

_found2: cmp [edi + 4], 0x4c4c442e // '.DLL' 
jnz _notfound 

inc ecx 
shl ecx, 2 
mov eax, dwSize 
and eax, 0xfffffffc 
sub eax, ecx 
mov _nOffset, eax 
jmp _done 

_notfound: 
cmp ecx, 8 
ja _loop 

_done: 
} 

} 
else 
{ 
return false; 
} 

UnmapViewOfFile(pMapMem); 


DWORD dwAddressOffset = _nOffset - 0x70; 
CloseHandle(hMap); 
CloseHandle(hFile); 




char buff[512]; 
char libbuff[1024]; 
GetSystemDirectory(buff, 512); 


DWORD a[24]; 
HINSTANCE h; 
memset(a, 0, 24 * sizeof(DWORD)); 

a[0] = (DWORD)LoadLibrary; 
a[1] = (DWORD)GetProcAddress; 
a[2] = (DWORD)ExitProcess; 

a[4] = (DWORD)RegCloseKey; 

strcpy(libbuff, buff); 
strcat(libbuff, "\\comdlg32.dll"); 
h = LoadLibrary(libbuff); 
if (h) 
{ 
a[6] = (DWORD)GetProcAddress(h, "PrintDlgA");; 
FreeLibrary(h); 
} 

strcpy(libbuff, buff); 
strcat(libbuff, "\\crypt32.dll"); 
h = LoadLibrary(libbuff); 
if (h) 
{ 
a[8] = (DWORD)GetProcAddress(h, "CertOpenStore");; 
FreeLibrary(h); 
} 

a[10] = (DWORD)::DPtoLP; 

strcpy(libbuff, buff); 
strcat(libbuff, "\\netapi32.dll"); 
h = LoadLibrary(libbuff); 
if (h) 
{ 
a[12] = (DWORD)GetProcAddress(h, "Netbios"); 
FreeLibrary(h); 
} 
a[14] = (DWORD)CoInitialize; 
a[16] = (DWORD)ExtractIconA; 
a[18] = (DWORD)::GetDC; 

strcpy(libbuff, buff); 
strcat(libbuff, "\\wininet.dll"); 
h = LoadLibrary(libbuff); 
if (h) 
{ 
a[20] = (DWORD)GetProcAddress(h, "InternetOpenA");; 
FreeLibrary(h); 
} 

strcpy(libbuff, buff); 
strcat(libbuff, "\\winmm.dll"); 
h = LoadLibrary(libbuff); 
if (h) 
{ 
a[22] = (DWORD)GetProcAddress(h, "joyGetPos");; 
FreeLibrary(h); 
} 


CFile f; 
if (f.Open(strOrigGame, CFile::modeReadWrite)) 
{ 
f.Seek(dwAddressOffset, CFile::begin); 
f.Write(a, 24 * sizeof(DWORD)); 
f.Close(); 
} 
else 
{ 
return false; 
} 


return true; 
} 


---------------------------------------------------
These informations are for educative purpose only!|
---------------------------------------------------