I haven't released anything in a while because I was busy working on all sorts of things including this project.
note that macro's in VC++ preprocessor are very picky, a space (or any character after a '\' character) can F*ckup your macro and block compilation. When facing these problems make sure there are no spaces between the macro name and it's opening bracket
Like this:
#define A(
This is wrong:
#define A (
Also make sure there are no other characters after a '\'
Like this:
#define A( a,b )\d <- this will f*ck things up for you real bad!
The code that injects and parses all the strings is a bit messy and undocumented so you might want to write your own injection/parser to do the job for you.
So what's this anyway?
I wrote a few macros that contain offset-independent assembler code. Which you can use even if you don't know any assembler. If you do know assembler they will probably speed up the process of writing offset independent code.
Why use this?
If you want to test a pointer without writing a whole dll to do it. Or if a game is protected in such a fashion that it becomes unfeasible to inject a dll file. Or if for some reason you find my semi-marco language smexy(er then C++)
What's offset independence?
If code is offset independent it means that it can run from
any memory address. Because jumps, calls, variables and pointers are all offset
dependent it's generally very hard to write offset independent code in high-level languages, since your compiler assumes that your code will always be located at a static address. Most of the time if you want offset independent code you'll have to use the assembler language or a language that lets you build your own stack frame and allocate your own variables from the stack.
The macros and examples
I've included 14 macro's which enable you to:
Call winapi functions like MessageBox, GetAsyncKeyState, etc.
Manage variables and pointers (named 1, 2, 3...n)
Create labels
Create basic if/ifnot structures
All variables have numeric names, so instead of having: int abc = 0, you will have: int 1 = 0;
All parameters for api calls must be passed backwards, Meaning that the last parameter to a function is the first variable pushed and vise versa.
Eg. if you have a function that waits for the paramters 1, 2, 3
you push:
3, 2, 1 <api call goes here>
The api calling system has a limitation (too keep it all as simple as possible). All the variables you pass to a function must be in a sequential order, meaning that you can't pass variable 1, 5, and 3 in that order. If you need to pass variables you'll have to keep these two things in mind (the reverse passing and the sequentiality)
Here's a example function that calls MessageBoxA in a remote process and works on
any address.
Code:
char* ApiName = "MessageBoxA";
char* Text= "Hello offset independent world!";
char* Title = "SCHiM";
void __declspec( naked ) RemoteMessageBoxFucntion(){
STARTS(4)
SAVE_PERSPECTIVE( 1 )
MOV_I( 3, NULL )
MOV_I_STR( 2, Text)
MOV_I_STR( 1, Title )
MOV_I( 0, MB_OK )
APICALLER( ApiName, 0, 3, GKsooak )
LOAD_PERSPECTIVE( 1 )
ENDS(4)
}
When this function is injected into another process it will pop-up a messagebox saying: "Hello offset independent world!" it's title will be: "SCHiM".
The function starts with the STARTS( number of variables go here ) macro:
This macro will allocate space for 4 variables from the stack. Just like arrays, the the variables allocated from the stack have a base index of 0. This means that the first variable you can access is named 0 and the last (the fourth) is named 3.
Note that variable 4 is not a valid variable and will probably be corrupted during program execution.
The next macro in the function is SAVE_PERSPECTIVE( this value is always 1 ):
Code:
SAVE_PERSPECTIVE( 1 )
This macro will save the current stack pointer ( ESP, your current perspective on the stack) in a location relative to your frame pointer ( EBP ). Since EBP will never be touched by any WINAPI functions this is the ideal register to save such important data on. You should call this right after STARTS()
Then we have MOV_I( variable name goes here, data goes here ):
This macro is derived from
move
immidiate operand. This macro moves NULL into variable 3 (var_n from now on)
Then comes the string operand MOV_I_STR( variable goes here, pointer to string goes here):
Code:
MOV_I_STR( 2, Text)
This macro is also very easy, and is derived from
move
immidiate
string. This marco moves a char* to variable 2, during the injection the string is also automatically written into the remote process.
Now comes the real deal APICALLER( api name goes here, starting variable, ending variable, random (this can be anything) )
Code:
APICALLER( ApiName, 0, 3, GKsooak )
This marco is a bit harder. First it needs a pointer to an api name, in the injection process this pointer is translated to a call to that api. Next it needs the first variable to push on the stack. Then it expects the ending variable where the stack-push-loop will end (this is why the pushing process is sequential) The last thing it needs is a random string of characters.
The last operand can really be
anything it's just there to provide a unique label during compilation and linking and is no longer present when injecting.
LOAD_PERSPECTIVE( this value is always 1 ):
Code:
LOAD_PERSPECTIVE( 1 )
This macro receives the previous perspective ( esp ) after an api call or when the stack is corrupted ( thus fixing the stack ). It should be called every time you call an API function and before ENDS()
Last but not least comes ENDS( number of variables used go here ):
This macro deallocates all variables and fixes the stack so that you can safely return.
This is another example:
Code:
char* ApiName = "MessageBoxA";
char* GetAsyncKeyStater = "GetAsyncKeyState";
char* StringName = "Hello offset independent world!";
char* Title = "SCHiM";
void __declspec( naked ) RemoteMessageBoxFucntion(){
STARTS(4) // allocate variables and save registers
SAVE_PERSPECTIVE( 1 ) // save the stack
LOCATION( NoInsert ) // NoInsert:
LOAD_PERSPECTIVE( 1 ) // load the stack
MOV_I( 0, VK_INSERT ) // var_0 = VK_INSERT
APICALLER( GetAsyncKeyStater, 0, 0, agfjsdigfjsd ) // call an api
API_ERROR( 0, NoInsert ) // check the return value
MOV_I( 3, NULL ) // var_3 = NULL
MOV_I_STR( 2, StringName ) // var_2 = (char*) str
MOV_I_STR( 1, Title ) // var_1 = (char*) title
MOV_I( 0, MB_OK ) // var_0 = MB_OK
APICALLER( ApiName, 0, 3, GKsooak ) // call api
LOAD_PERSPECTIVE( 1 ) // load stack
ENDS(4) // deallocate variables and load registers
}
This function waits for a key press (insert) before showing a message box
Here we see 2 new macros LOCATION and API_ERROR. LOCATION is very simple, it defines a location in the code much like a goto statement. After a LOCATION statement you can use the parameter just like you would use an ordinary label.
API_ERROR is not very hard either, it checks the return value of the api. If the return value matches the operand a jump is made to the location specified in the second operand.
So these macros:
Code:
LOCATION( NoInsert )
APICALLER( GetAsyncKeyStater, 0, 0, agfjsdigfjsd )
API_ERROR( 0, NoInsert )
would look like this in Cpp or C
Code:
NoInsert : // LOCATION ( NoInsert )
if( GetAsyncKeyStater(VK_INSERT) == 0 ){ // APICALLER( name, 0, 0, label)
// API_ERROR(0, NoInsert )
goto NoInsert; // this will not compile, but it illustrates what we are doing here quite well.
}
two last example that'll show you how to use pointers and loops:
Code:
void __declspec( naked ) RemoteMessageBoxFucntion(){
STARTS(4) // save registers and allocate variables
SAVE_PERSPECTIVE( 1 ) // save the stack
MOV_I( 0, 0 ) // variable 0 = NULL
MOV_I( 1, 8 ) // variable 1 = 8
LOCATION( LOOP ) // LOOP:
ADD_I( 0, 1 ) // var_0++
IFNOT( 0, 1, LOOP ) // if ( var_0 != var_1) { goto LOOP; }
LOAD_PERSPECTIVE( 1 ) // load the stack
ENDS(4) // load the registers and deallocate the variables
}
And now pointers:
Code:
void __declspec( naked ) RemoteMessageBoxFucntion(){
STARTS(4)
SAVE_PERSPECTIVE( 1 )
MOV_I( 0, 0xDEADBEEF ) // var_0 = 0xDEAFBEEF;
MOV_I( 1, 0x90909090 ) // var_1 = 0x90909090 = NOP NOP NOP NOP
MOV_P( 0, 1 ) // *var_0 = var_1;
LOAD_PERSPECTIVE( 1 )
ENDS(4)
}
There are two macros I haven't covered yet, but those are really simple. The first is MOV_V( var_here, 2nd_var_here ) which copies 2nd_var_here to var_here. The second is IF( var_1, var_2, True_loc ) which translates to:
Code:
if( var_1 == var_2 ){
goto True_loc;
}
The complete source
This is the complete program, it's a console application that when started looks for a window tittled OllyDbg - [CPU] and when found injects a function into olly's process.
Console application, main.cpp:
Code:
#include "HsAsm.h"
#include <windows.h>
char* ApiName = "MessageBoxA";
char* GetAsyncKeyStater = "GetAsyncKeyState";
char* StringName = "Hello offset independent world!";
char* Title = "SCHiM";
void __declspec( naked ) RemoteMessageBoxFucntion(){
STARTS(4)
SAVE_PERSPECTIVE( 1 )
LOCATION( NoInsert )
LOAD_PERSPECTIVE( 1 )
MOV_I( 0, VK_INSERT )
APICALLER( GetAsyncKeyStater, 0, 0, agfjsdigfjsd )
API_ERROR( 0, NoInsert )
MOV_I( 3, NULL )
MOV_I_STR( 2, StringName )
MOV_I_STR( 1, Title )
MOV_I( 0, MB_OK )
APICALLER( ApiName, 0, 3, GKsooak )
LOAD_PERSPECTIVE( 1 )
ENDS(4)
}
int main(){
HWND hWnd = FindWindow(0, "OllyDbg - [CPU]");
unsigned long PID;
GetWindowThreadProcessId(hWnd, &PID);
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
WriteRemoteCode( (char*)0x100000, (char*) &RemoteMessageBoxFucntion, 250, hProc);
}
HsAsm.h:
Code:
#ifndef HS_ASM_H
#define HS_ASM_H
#define APICALLER( API_NAME, START_INDEX, STOP_INDEX, RANDOM_TOKEN ) __asm\
{ \
__asm xor esi, esi \
__asm mov edi, esp \
__asm RANDOM_TOKEN: \
__asm mov eax, START_INDEX \
__asm add eax, esi \
__asm shl eax, 2 \
__asm mov ebx, dword ptr[edi+eax] \
__asm push ebx \
__asm inc esi \
__asm shr eax, 2 \
__asm cmp eax, STOP_INDEX \
__asm jne RANDOM_TOKEN \
__asm cli \
__asm cld \
__asm cli \
__asm cld \
__asm mov eax, API_NAME \
}
#define LOAD_PERSPECTIVE( PERSPECTIVE_EBP_INDEX ) __asm \
{ \
__asm mov eax, PERSPECTIVE_EBP_INDEX \
__asm shl eax, 2 \
__asm push ebx \
__asm mov ebx, ebp \
__asm sub ebx, eax \
__asm mov eax, ebx \
__asm pop ebx \
__asm mov esp, dword ptr[eax] \
}
#define SAVE_PERSPECTIVE( PERSPECTIVE_EBP_INDEX ) __asm \
{ \
__asm mov eax, PERSPECTIVE_EBP_INDEX \
__asm shl eax, 2 \
__asm push ebx \
__asm mov ebx, ebp \
__asm sub ebx, eax \
__asm mov dword ptr[ebx], esp \
__asm add dword ptr[ebx], 4 \
__asm pop ebx \
}
#define API_ERROR( DELIM_IMM32, ERR_L ) __asm \
{ \
__asm cmp eax, DELIM_IMM32 \
__asm je ERR_L \
}
#define ADD_I( INDEX_D, IMM32 ) __asm \
{ \
__asm mov eax, INDEX_D \
__asm shl eax, 2 \
__asm add dword ptr[esp+eax], IMM32 \
}
#define LOCATION( LABELNAME ) __asm LABELNAME:
#define IF( INDEX_D, INDEX_S, TRUE_L ) __asm \
{ \
__asm mov eax, INDEX_D \
__asm shl eax, 2 \
__asm add eax, 4 \
__asm push ebx \
__asm mov ebx, dword ptr [esp+eax] \
__asm mov eax, INDEX_S \
__asm shl eax, 2 \
__asm add eax, 4 \
__asm cmp ebx, dword ptr [esp+eax] \
__asm pop ebx \
__asm je TRUE_L \
}
#define IFNOT( INDEX_D, INDEX_S, FALSE_L ) __asm \
{ \
__asm mov eax, INDEX_D \
__asm shl eax, 2 \
__asm add eax, 4 \
__asm push ebx \
__asm mov ebx, dword ptr [esp+eax] \
__asm mov eax, INDEX_S \
__asm shl eax, 2 \
__asm add eax, 4 \
__asm cmp ebx, dword ptr [esp+eax] \
__asm pop ebx \
__asm jnz FALSE_L \
}
#define MOV_V( INDEX_D, INDEX_S ) __asm \
{ \
__asm mov eax, INDEX_S \
__asm shl eax, 2 \
__asm add eax, 4 \
__asm push ebx \
__asm mov ebx, dword ptr[esp+eax] \
__asm mov eax, INDEX_D \
__asm shl eax, 2 \
__asm add eax, 4 \
__asm mov dword ptr[esp+eax], ebx \
__asm pop ebx \
}
#define MOV_I_STR( INDEX_D, STRNAME ) __asm \
{ \
__asm mov eax, STRNAME \
__asm push ecx \
__asm mov ecx, INDEX_D \
__asm shl ecx, 2 \
__asm add ecx, 4 \
__asm mov dword ptr[esp+ecx], eax \
__asm pop ecx \
}
#define MOV_P( INDEX_PTR_D, INDEX_S ) __asm \
{ \
__asm mov eax, INDEX_S \
__asm shl eax, 2 \
__asm add eax, 4 \
__asm push ebx \
__asm mov ebx, dword ptr[esp+eax] \
__asm mov eax, INDEX_PTR_D \
__asm shl eax, 2 \
__asm add eax, 4 \
__asm mov eax, dword ptr[esp+eax] \
__asm mov dword ptr[eax], ebx \
__asm pop ebx \
}
#define MOV_I( INDEX_D, IMM32 ) __asm \
{ \
__asm mov eax, INDEX_D \
__asm shl eax, 2 \
__asm mov dword ptr[esp+eax], IMM32 \
}
#define STARTS( VARIABLES ) __asm \
{ \
__asm push ebp \
__asm mov ebp, esp \
__asm push 0 \
__asm pushad \
__asm mov eax, VARIABLES \
__asm shl eax, 2 \
__asm sub esp, eax \
}
#define ENDS( VARIABLES) __asm \
{ \
__asm mov eax, VARIABLES \
__asm shl eax,2 \
__asm add esp, eax \
__asm popad \
__asm mov esp, ebp \
__asm pop ebp \
__asm ret \
}
extern bool WriteRemoteCode(char* lpRemoteAddress, char* lpLocalAddress, long Size, void* hProc);
#endif
HsAsm.cpp:
Code:
#include "HsAsm.h"
#include <windows.h>
bool bCompare(const BYTE* pData, const BYTE* bMask, const char* szMask){
__try{
for(;*szMask;++szMask,++pData,++bMask){
if(*szMask=='x' && *pData!=*bMask){
return false;
}
}
} __except(1){
return false;
}
return (*szMask) == NULL;
}
long GetBruteProcAddress( char* ApiName ){
HANDLE hKernelModule = GetModuleHandle("kernel32.dll");
HANDLE hUserModule = GetModuleHandle("User32.dll");
if( GetLastError() == 0x7E ){
hUserModule = LoadLibrary("User32.dll");
}
char *RealApiName = NULL;
__asm{
mov eax, ApiName
mov eax, [eax]
mov eax, [eax]
mov RealApiName, eax
}
long Returner = (long) GetProcAddress( (HINSTANCE__*) hKernelModule, RealApiName);
if( Returner == NULL ){
Returner = (long) GetProcAddress( (HINSTANCE__*) hUserModule, RealApiName );
}
return Returner;
}
long WriteStringToPoc( char* lStr, HANDLE hProc ){
char *String = NULL;
__asm{
mov eax, lStr
mov eax, [eax]
mov eax, [eax]
mov String, eax
}
void* StringLocation = VirtualAllocEx( hProc, NULL, strlen( String ), MEM_COMMIT, 0x40 );
if(!StringLocation){
return NULL;
}
if(!WriteProcessMemory( hProc, StringLocation, (void*)String, strlen(String), NULL)){
return NULL;
}
return (long)StringLocation;
}
bool WriteRemoteCode(char* lpRemoteAddress, char* lpLocalAddress, long Size, void* hProc){
// E8 adr adr adr adr nop nop nop nop
char* APISignature = "\xFA\xFC\xFA\xFC\xA1\x00\x00\x00\x00";
char* StrSignature = "\xA1\x00\x00\x00\x00\x51\xB9\x01\x00\x00\x00\xC1\xE1\x02\x83\xC1\x04\x89\x04\x0C\x59";
// x ? ? ? ? x x ? ? ? ? x x x x x x x x x x
long OldProtect = NULL;
char *Buffer = new char[Size];
for(long i = 0; i != Size; i++){
if( bCompare( (BYTE*)(lpLocalAddress+i),(BYTE*)APISignature, "xxxxx????") != false ){
Buffer[i] = '\xE8';
*reinterpret_cast< long* >( &Buffer[i+1] ) = ((char*)GetBruteProcAddress( (char*)&lpLocalAddress[i+5] ) - &lpRemoteAddress[i] - 5 );
i += 5;
for(int y = 0; y != 4; y++){
Buffer[i+y] = '\x90';
}
i += 3;
} else if( bCompare( (BYTE*)(lpLocalAddress+i),(BYTE*)StrSignature, "x????xx????xxxxxxxxxx") != false ){
Buffer[i] = '\xB8';
*reinterpret_cast< long* >( &Buffer[i+1] ) = WriteStringToPoc( (char*)&lpLocalAddress[i+1], hProc );
i += 4;
} else {
Buffer[i] = lpLocalAddress[i];
}
}
if( !VirtualAllocEx( hProc, lpRemoteAddress, Size, MEM_COMMIT, 0x40 ) )
return false;
if( !WriteProcessMemory( hProc, (void*)lpRemoteAddress, (void*)Buffer, Size, NULL ) )
return false;
if ( !CreateRemoteThread( hProc, NULL, 0, (LPTHREAD_START_ROUTINE)lpRemoteAddress, NULL, 0, NULL ) )
return false;
return true;
}
Bugs errors and drawbacks
There are several
*Api calls must be reversed and sequential
*The library of the API may not have been loaded into the remote application, resulting in an access violation. However all applications that have a window have User32.dll loaded and Kernel32.dll is always loaded. Therefore I've included these libraries in my code, if you need more you'll have to do it yourself
-SCHiM