asm/asm.c
author Matt Woodrow <pred@alliedmods.net>
Fri Feb 20 15:24:04 2009 +1300 (2009-02-20)
changeset 0 4c53fd0b014e
permissions -rw-r--r--
IMPORT
[email protected]
     1
#include "asm.h"
[email protected]
     2
[email protected]
     3
#ifndef WIN32
[email protected]
     4
#define _GNU_SOURCE
[email protected]
     5
#include <dlfcn.h>
[email protected]
     6
#include <string.h>
[email protected]
     7
[email protected]
     8
#define REG_EAX			0
[email protected]
     9
#define REG_ECX			1
[email protected]
    10
#define REG_EDX			2
[email protected]
    11
#define REG_EBX			3
[email protected]
    12
[email protected]
    13
#define IA32_MOV_REG_IMM		0xB8	// encoding is +r <imm32>
[email protected]
    14
#endif
[email protected]
    15
[email protected]
    16
extern void Msg( const char *, ... );
[email protected]
    17
[email protected]
    18
/**
[email protected]
    19
* Checks if a call to a fpic thunk has just been written into dest.
[email protected]
    20
* If found replaces it with a direct mov that sets the required register to the value of pc.
[email protected]
    21
*
[email protected]
    22
* @param dest		Destination buffer where a call opcode + addr (5 bytes) has just been written.
[email protected]
    23
* @param pc		The program counter value that needs to be set (usually the next address from the source).
[email protected]
    24
* @noreturn
[email protected]
    25
*/
[email protected]
    26
void check_thunks(unsigned char *dest, unsigned char *pc)
[email protected]
    27
{
[email protected]
    28
#if defined WIN32
[email protected]
    29
	return;
[email protected]
    30
#else
[email protected]
    31
	/* Step write address back 4 to the start of the function address */
[email protected]
    32
	unsigned char *writeaddr = dest - 4;
[email protected]
    33
	unsigned char *calloffset = *(unsigned char **)writeaddr;
[email protected]
    34
	unsigned char *calladdr = (unsigned char *)(dest + (unsigned int)calloffset);
[email protected]
    35
[email protected]
    36
	/* Lookup name of function being called */
[email protected]
    37
	if ((*calladdr == 0x8B) && (*(calladdr+2) == 0x24) && (*(calladdr+3) == 0xC3))
[email protected]
    38
	{
[email protected]
    39
		//a thunk maybe?
[email protected]
    40
		char movByte = IA32_MOV_REG_IMM;
[email protected]
    41
[email protected]
    42
		/* Calculate the correct mov opcode */
[email protected]
    43
		switch (*(calladdr+1))
[email protected]
    44
		{
[email protected]
    45
		case 0x04:
[email protected]
    46
			{
[email protected]
    47
				movByte += REG_EAX;
[email protected]
    48
				break;
[email protected]
    49
			}
[email protected]
    50
		case 0x1C:
[email protected]
    51
			{
[email protected]
    52
				movByte += REG_EBX;
[email protected]
    53
				break;
[email protected]
    54
			}
[email protected]
    55
		case 0x0C:
[email protected]
    56
			{
[email protected]
    57
				movByte += REG_ECX;
[email protected]
    58
				break;
[email protected]
    59
			}
[email protected]
    60
		case 0x14:
[email protected]
    61
			{
[email protected]
    62
				movByte += REG_EDX;
[email protected]
    63
				break;
[email protected]
    64
			}
[email protected]
    65
		default:
[email protected]
    66
			{
[email protected]
    67
				Msg("Unknown thunk: %c\n", *(calladdr+1));
[email protected]
    68
				break;
[email protected]
    69
			}
[email protected]
    70
		}
[email protected]
    71
[email protected]
    72
		/* Move our write address back one to where the call opcode was */
[email protected]
    73
		writeaddr--;
[email protected]
    74
[email protected]
    75
[email protected]
    76
		/* Write our mov */
[email protected]
    77
		*writeaddr = movByte;
[email protected]
    78
		writeaddr++;
[email protected]
    79
[email protected]
    80
		/* Write the value - The provided program counter value */
[email protected]
    81
		*(void **)writeaddr = (void *)pc;
[email protected]
    82
		writeaddr += 4;
[email protected]
    83
	}
[email protected]
    84
[email protected]
    85
	return;
[email protected]
    86
#endif
[email protected]
    87
}
[email protected]
    88
[email protected]
    89
//if dest is NULL, returns minimum number of bytes needed to be copied
[email protected]
    90
//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
[email protected]
    91
//http://www.devmaster.net/forums/showthread.php?t=2311
[email protected]
    92
int copy_bytes(unsigned char *func, unsigned char* dest, int required_len) {
[email protected]
    93
	int bytecount = 0;
[email protected]
    94
[email protected]
    95
	while(bytecount < required_len && *func != 0xCC)
[email protected]
    96
	{
[email protected]
    97
		// prefixes F0h, F2h, F3h, 66h, 67h, D8h-DFh, 2Eh, 36h, 3Eh, 26h, 64h and 65h
[email protected]
    98
		int operandSize = 4;
[email protected]
    99
		int FPU = 0;
[email protected]
   100
		int twoByte = 0;
[email protected]
   101
		unsigned char opcode = 0x90;
[email protected]
   102
		unsigned char modRM = 0xFF;
[email protected]
   103
		while(*func == 0xF0 ||
[email protected]
   104
			  *func == 0xF2 ||
[email protected]
   105
			  *func == 0xF3 ||
[email protected]
   106
			 (*func & 0xFC) == 0x64 ||
[email protected]
   107
			 (*func & 0xF8) == 0xD8 ||
[email protected]
   108
			 (*func & 0x7E) == 0x62)
[email protected]
   109
		{
[email protected]
   110
			if(*func == 0x66)
[email protected]
   111
			{
[email protected]
   112
				operandSize = 2;
[email protected]
   113
			}
[email protected]
   114
			else if((*func & 0xF8) == 0xD8)
[email protected]
   115
			{
[email protected]
   116
				FPU = *func;
[email protected]
   117
				if (dest)
[email protected]
   118
						*dest++ = *func++;
[email protected]
   119
				else
[email protected]
   120
						func++;
[email protected]
   121
				bytecount++;
[email protected]
   122
				break;
[email protected]
   123
			}
[email protected]
   124
[email protected]
   125
			if (dest)
[email protected]
   126
				*dest++ = *func++;
[email protected]
   127
			else
[email protected]
   128
				func++;
[email protected]
   129
			bytecount++;
[email protected]
   130
		}
[email protected]
   131
[email protected]
   132
		// two-byte opcode byte
[email protected]
   133
		if(*func == 0x0F)
[email protected]
   134
		{
[email protected]
   135
			twoByte = 1;
[email protected]
   136
			if (dest)
[email protected]
   137
				*dest++ = *func++;
[email protected]
   138
			else
[email protected]
   139
				func++;
[email protected]
   140
			bytecount++;
[email protected]
   141
		}
[email protected]
   142
[email protected]
   143
		// opcode byte
[email protected]
   144
		opcode = *func++;
[email protected]
   145
		if (dest) *dest++ = opcode;
[email protected]
   146
		bytecount++;
[email protected]
   147
[email protected]
   148
		// mod R/M byte
[email protected]
   149
		modRM = 0xFF;
[email protected]
   150
		if(FPU)
[email protected]
   151
		{
[email protected]
   152
			if((opcode & 0xC0) != 0xC0)
[email protected]
   153
			{
[email protected]
   154
				modRM = opcode;
[email protected]
   155
			}
[email protected]
   156
		}
[email protected]
   157
		else if(!twoByte)
[email protected]
   158
		{
[email protected]
   159
			if((opcode & 0xC4) == 0x00 ||
[email protected]
   160
			   (opcode & 0xF4) == 0x60 && ((opcode & 0x0A) == 0x02 || (opcode & 0x09) == 0x09) ||
[email protected]
   161
			   (opcode & 0xF0) == 0x80 ||
[email protected]
   162
			   (opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02 ||
[email protected]
   163
			   (opcode & 0xFC) == 0xD0 ||
[email protected]
   164
			   (opcode & 0xF6) == 0xF6)
[email protected]
   165
			{
[email protected]
   166
				modRM = *func++;
[email protected]
   167
				if (dest) *dest++ = modRM;
[email protected]
   168
				bytecount++;
[email protected]
   169
			}
[email protected]
   170
		}
[email protected]
   171
		else
[email protected]
   172
		{
[email protected]
   173
			if((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D ||
[email protected]
   174
			   (opcode & 0xF0) == 0x30 ||
[email protected]
   175
			   opcode == 0x77 ||
[email protected]
   176
			   (opcode & 0xF0) == 0x80 ||
[email protected]
   177
			   (opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02 ||
[email protected]
   178
			   (opcode & 0xF8) == 0xC8)
[email protected]
   179
			{
[email protected]
   180
				// No mod R/M byte
[email protected]
   181
			}
[email protected]
   182
			else
[email protected]
   183
			{
[email protected]
   184
				modRM = *func++;
[email protected]
   185
				if (dest) *dest++ = modRM;
[email protected]
   186
				bytecount++;
[email protected]
   187
			}
[email protected]
   188
		}
[email protected]
   189
[email protected]
   190
		// SIB
[email protected]
   191
		if((modRM & 0x07) == 0x04 &&
[email protected]
   192
		   (modRM & 0xC0) != 0xC0)
[email protected]
   193
		{
[email protected]
   194
			if (dest)
[email protected]
   195
				*dest++ = *func++;   //SIB
[email protected]
   196
			else
[email protected]
   197
				func++;
[email protected]
   198
			bytecount++;
[email protected]
   199
		}
[email protected]
   200
[email protected]
   201
		// mod R/M displacement
[email protected]
   202
[email protected]
   203
		// Dword displacement, no base
[email protected]
   204
	if((modRM & 0xC5) == 0x05) {
[email protected]
   205
		if (dest) {
[email protected]
   206
			*(unsigned int*)dest = *(unsigned int*)func;
[email protected]
   207
			dest += 4;
[email protected]
   208
		}
[email protected]
   209
		func += 4;
[email protected]
   210
		bytecount += 4;
[email protected]
   211
	}
[email protected]
   212
[email protected]
   213
		// Byte displacement
[email protected]
   214
	if((modRM & 0xC0) == 0x40) {
[email protected]
   215
		if (dest)
[email protected]
   216
			*dest++ = *func++;
[email protected]
   217
		else
[email protected]
   218
			func++;
[email protected]
   219
		bytecount++;
[email protected]
   220
	}
[email protected]
   221
[email protected]
   222
		// Dword displacement
[email protected]
   223
	if((modRM & 0xC0) == 0x80) {
[email protected]
   224
		if (dest) {
[email protected]
   225
			*(unsigned int*)dest = *(unsigned int*)func;
[email protected]
   226
			dest += 4;
[email protected]
   227
		}
[email protected]
   228
		func += 4;
[email protected]
   229
		bytecount += 4;
[email protected]
   230
	}
[email protected]
   231
[email protected]
   232
		// immediate
[email protected]
   233
		if(FPU)
[email protected]
   234
		{
[email protected]
   235
			// Can't have immediate operand
[email protected]
   236
		}
[email protected]
   237
		else if(!twoByte)
[email protected]
   238
		{
[email protected]
   239
			if((opcode & 0xC7) == 0x04 ||
[email protected]
   240
			   (opcode & 0xFE) == 0x6A ||   // PUSH/POP/IMUL
[email protected]
   241
			   (opcode & 0xF0) == 0x70 ||   // Jcc
[email protected]
   242
			   opcode == 0x80 ||
[email protected]
   243
			   opcode == 0x83 ||
[email protected]
   244
			   (opcode & 0xFD) == 0xA0 ||   // MOV
[email protected]
   245
			   opcode == 0xA8 ||			// TEST
[email protected]
   246
			   (opcode & 0xF8) == 0xB0 ||   // MOV
[email protected]
   247
			   (opcode & 0xFE) == 0xC0 ||   // RCL
[email protected]
   248
			   opcode == 0xC6 ||			// MOV
[email protected]
   249
			   opcode == 0xCD ||			// INT
[email protected]
   250
			   (opcode & 0xFE) == 0xD4 ||   // AAD/AAM
[email protected]
   251
			   (opcode & 0xF8) == 0xE0 ||   // LOOP/JCXZ
[email protected]
   252
			   opcode == 0xEB ||
[email protected]
   253
			   opcode == 0xF6 && (modRM & 0x30) == 0x00)   // TEST
[email protected]
   254
			{
[email protected]
   255
				if (dest)
[email protected]
   256
					*dest++ = *func++;
[email protected]
   257
				else
[email protected]
   258
					func++;
[email protected]
   259
				bytecount++;
[email protected]
   260
			}
[email protected]
   261
		else if((opcode & 0xF7) == 0xC2) // RET
[email protected]
   262
			{
[email protected]
   263
				if (dest) {
[email protected]
   264
					*(unsigned short*)dest = *(unsigned short*)func;
[email protected]
   265
					dest += 2;
[email protected]
   266
				}
[email protected]
   267
				func += 2;
[email protected]
   268
				bytecount += 2;
[email protected]
   269
			}
[email protected]
   270
			else if((opcode & 0xFC) == 0x80 ||
[email protected]
   271
					(opcode & 0xC7) == 0x05 ||
[email protected]
   272
					(opcode & 0xF8) == 0xB8 ||
[email protected]
   273
					(opcode & 0xFE) == 0xE8 ||	  // CALL/Jcc
[email protected]
   274
					(opcode & 0xFE) == 0x68 ||
[email protected]
   275
					(opcode & 0xFC) == 0xA0 ||
[email protected]
   276
					(opcode & 0xEE) == 0xA8 ||
[email protected]
   277
					opcode == 0xC7 ||
[email protected]
   278
					opcode == 0xF7 && (modRM & 0x30) == 0x00)
[email protected]
   279
			{
[email protected]
   280
				if (dest) {
[email protected]
   281
					//Fix CALL/JMP offset
[email protected]
   282
					if ((opcode & 0xFE) == 0xE8) {
[email protected]
   283
						if (operandSize == 4)
[email protected]
   284
						{
[email protected]
   285
							*(long*)dest = ((func + *(long*)func) - dest);
[email protected]
   286
[email protected]
   287
							//pRED* edit. func is the current address of the call address, +4 is the next instruction, so the value of $pc
[email protected]
   288
							check_thunks(dest+4, func+4);
[email protected]
   289
						}
[email protected]
   290
						else
[email protected]
   291
							*(short*)dest = ((func + *(short*)func) - dest);
[email protected]
   292
[email protected]
   293
					} else {
[email protected]
   294
						if (operandSize == 4)
[email protected]
   295
							*(unsigned long*)dest = *(unsigned long*)func;
[email protected]
   296
						else
[email protected]
   297
							*(unsigned short*)dest = *(unsigned short*)func;
[email protected]
   298
					}
[email protected]
   299
					dest += operandSize;
[email protected]
   300
				}
[email protected]
   301
				func += operandSize;
[email protected]
   302
				bytecount += operandSize;
[email protected]
   303
[email protected]
   304
			}
[email protected]
   305
		}
[email protected]
   306
		else
[email protected]
   307
		{
[email protected]
   308
			if(opcode == 0xBA ||			// BT
[email protected]
   309
			   opcode == 0x0F ||			// 3DNow!
[email protected]
   310
			   (opcode & 0xFC) == 0x70 ||   // PSLLW
[email protected]
   311
			   (opcode & 0xF7) == 0xA4 ||   // SHLD
[email protected]
   312
			   opcode == 0xC2 ||
[email protected]
   313
			   opcode == 0xC4 ||
[email protected]
   314
			   opcode == 0xC5 ||
[email protected]
   315
			   opcode == 0xC6)
[email protected]
   316
			{
[email protected]
   317
				if (dest)
[email protected]
   318
					*dest++ = *func++;
[email protected]
   319
				else
[email protected]
   320
					func++;
[email protected]
   321
			}
[email protected]
   322
			else if((opcode & 0xF0) == 0x80) // Jcc -i
[email protected]
   323
			{
[email protected]
   324
				if (dest) {
[email protected]
   325
					if (operandSize == 4)
[email protected]
   326
						*(unsigned long*)dest = *(unsigned long*)func;
[email protected]
   327
					else
[email protected]
   328
						*(unsigned short*)dest = *(unsigned short*)func;
[email protected]
   329
[email protected]
   330
					dest += operandSize;
[email protected]
   331
				}
[email protected]
   332
				func += operandSize;
[email protected]
   333
				bytecount += operandSize;
[email protected]
   334
			}
[email protected]
   335
		}
[email protected]
   336
	}
[email protected]
   337
[email protected]
   338
	return bytecount;
[email protected]
   339
}
[email protected]
   340
[email protected]
   341
//insert a specific JMP instruction at the given location
[email protected]
   342
void inject_jmp(void* src, void* dest) {
[email protected]
   343
	*(unsigned char*)src = OP_JMP;
[email protected]
   344
	*(long*)((unsigned char*)src+1) = (long)((unsigned char*)dest - ((unsigned char*)src + OP_JMP_SIZE));
[email protected]
   345
}
[email protected]
   346
[email protected]
   347
//fill a given block with NOPs
[email protected]
   348
void fill_nop(void* src, unsigned int len) {
[email protected]
   349
	unsigned char* src2 = (unsigned char*)src;
[email protected]
   350
	while (len) {
[email protected]
   351
		*src2++ = OP_NOP;
[email protected]
   352
		--len;
[email protected]
   353
	}
[email protected]
   354
}
[email protected]
   355
[email protected]
   356
void* eval_jump(void* src) {
[email protected]
   357
	unsigned char* addr = (unsigned char*)src;
[email protected]
   358
[email protected]
   359
	if (!addr) return 0;
[email protected]
   360
[email protected]
   361
	//import table jump
[email protected]
   362
	if (addr[0] == OP_PREFIX && addr[1] == OP_JMP_SEG) {
[email protected]
   363
		addr += 2;
[email protected]
   364
		addr = *(unsigned char**)addr;
[email protected]
   365
		//TODO: if addr points into the IAT
[email protected]
   366
		return *(void**)addr;
[email protected]
   367
	}
[email protected]
   368
[email protected]
   369
	//8bit offset
[email protected]
   370
	else if (addr[0] == OP_JMP_BYTE) {
[email protected]
   371
		addr = &addr[OP_JMP_BYTE_SIZE] + *(char*)&addr[1];
[email protected]
   372
		//mangled 32bit jump?
[email protected]
   373
		if (addr[0] = OP_JMP) {
[email protected]
   374
			addr = addr + *(int*)&addr[1];
[email protected]
   375
		}
[email protected]
   376
		return addr;
[email protected]
   377
	}
[email protected]
   378
	/*
[email protected]
   379
	//32bit offset
[email protected]
   380
	else if (addr[0] == OP_JMP) {
[email protected]
   381
		addr = &addr[OP_JMP_SIZE] + *(int*)&addr[1];
[email protected]
   382
	}
[email protected]
   383
	*/
[email protected]
   384
[email protected]
   385
	return addr;
[email protected]
   386
}
[email protected]
   387
/*
[email protected]
   388
from ms detours package
[email protected]
   389
static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
[email protected]
   390
{
[email protected]
   391
	MEMORY_BASIC_INFORMATION mbi;
[email protected]
   392
	VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));
[email protected]
   393
	__try {
[email protected]
   394
		PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
[email protected]
   395
		if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
[email protected]
   396
			return false;
[email protected]
   397
		}
[email protected]
   398
[email protected]
   399
		PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
[email protected]
   400
														  pDosHeader->e_lfanew);
[email protected]
   401
		if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
[email protected]
   402
			return false;
[email protected]
   403
		}
[email protected]
   404
[email protected]
   405
		if (pbAddress >= ((PBYTE)pDosHeader +
[email protected]
   406
						  pNtHeader->OptionalHeader
[email protected]
   407
						  .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&
[email protected]
   408
			pbAddress < ((PBYTE)pDosHeader +
[email protected]
   409
						 pNtHeader->OptionalHeader
[email protected]
   410
						 .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
[email protected]
   411
						 pNtHeader->OptionalHeader
[email protected]
   412
						 .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {
[email protected]
   413
			return true;
[email protected]
   414
		}
[email protected]
   415
		return false;
[email protected]
   416
	}
[email protected]
   417
	__except(EXCEPTION_EXECUTE_HANDLER) {
[email protected]
   418
		return false;
[email protected]
   419
	}
[email protected]
   420
}
[email protected]
   421
*/