I hope someone will find this intresting enough to acutally test it. I worked hard and long to further my knowledge about the windows kernel and this is the result of my studies.
With this tool you can disassemble (any) binary file running in your systems' memory. This tool can be easily tweaked to dump files on your disk as well.
I take credits for the driver and the conversion of the disassembler source (it was originally made to work with PE files on the disk)
The disassembly part itself was made by somebody else.
use it as your own risk.
I'm not responsible for ANY damage to your system or yourself or those around you.
After the driver has been loaded into memory you can obtain a handle to it by calling GreateFile(). Using this handle you can now read an write data to the driver (ReadFile/WriteFile). Using WriteFile() You can send commands to the driver, this is a list of all available commands:
Directly after a command has been sent, the usermode application must send the arguments to that specific command. For example, if the usermode applications sends the WriteFile(TARGET_SET") the next write file must contain the target name.
The driver must be loaded before the target is, the TARGET_SET, DUMP_DATA_SET, PROC_LOG_START must be set first. When you're ready to dump the file, send DUMP_DUMP wait a few seconds and call ReadFile() on the driver. The data returned are the copied instructions at the specified offset with the specified length.
Code:
#include <Ntifs.h>
#include <wdm.h>
#include <Ntddk.h>
#include <Ntstrsafe.h>
#define IO_TYPE 0
#define USE_WRITE_FUNCTION WriteNeither
VOID Unload(PDRIVER_OBJECT DriverObject);
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath);
NTSTATUS Create(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS Close(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS IoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS ReadNeither(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS WriteNeither(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS UnSupportedFunction(PDEVICE_OBJECT DeviceObject, PIRP Irp);
BOOLEAN IsStringTerminated(PCHAR pString, unsigned int uiLength);
BOOLEAN CompareStrings(PCHAR pString1, PCHAR pString2);
void ModuleDumperThread();
void INIT_ProcessCallback(IN HANDLE hParentId, IN HANDLE hProcessId, IN BOOLEAN bCreate);
void ClearBuffer(PCHAR Buffer, unsigned int Length);
void Timeout(INT64 Timout);
unsigned int StrLenKernelSafe(PCHAR pString);
typedef PCHAR (*GET_PROCESS_IMAGE_NAME) (PEPROCESS Process);
typedef NTSTATUS (*QUERY_INFO_PROCESS) (HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
typedef NTSTATUS (*ZWREADVIRTUAL) (HANDLE ProcessHandle, PVOID BaseAddress, PVOID Buffer, ULONG BufferLength, PULONG ReturnLength);
QUERY_INFO_PROCESS gZwQueryprocess;
GET_PROCESS_IMAGE_NAME gGetProcessImageFileName;
ZWREADVIRTUAL gZwReadVirtualMemory;
BOOLEAN IsLoggerOn = FALSE;
BOOLEAN Print = FALSE;
BOOLEAN IsPayloadCall = FALSE;
BOOLEAN IsRegisterTarget = FALSE;
BOOLEAN IsSupplyDumpData = FALSE;
BOOLEAN IsDumpWhenPossible = FALSE;
BOOLEAN IsDumpDumped = FALSE;
typedef struct _RTL_USER_PROCESS_PARAMETERS {
CHAR Reserved1[16];
PVOID Reserved2[10];
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
typedef struct _PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY LoadOrder;
LIST_ENTRY MemoryOrder;
LIST_ENTRY InitializationOrder;
PVOID ModuleBaseAddress;
PVOID EntryPoint;
ULONG ModuleSize;
UNICODE_STRING FullModuleName;
UNICODE_STRING ModuleName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY Hash;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
ULONG TimeStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
typedef struct _PEB {
CHAR Reserved1[2];
CHAR BeingDebugged;
CHAR Reserved2[1];
PVOID Reserved;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
CHAR Reserved4[104];
PVOID Reserved5[52];
PVOID PostProcessInitRoutine;
CHAR Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId;
} PEB, *PPEB;
HANDLE hThreadHandle;
HANDLE hgtPid;
ULONG SizeOfDump;
ULONG AddressOfDump;
CHAR Target[100];
CHAR Buffer1[200];
PCHAR TargetDump;
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPath){
NTSTATUS NtStatus = STATUS_SUCCESS;
unsigned int uiIndex = 0;
PDEVICE_OBJECT pDeviceObject = NULL;
UNICODE_STRING usDriverName, usDosDeviceName, sPsGetProcessImageFileName, routineName, sZwReadVirtualMemory;
DbgPrint("DriverEntry Called \r\n");
RtlInitUnicodeString(&sPsGetProcessImageFileName, L"PsGetProcessImageFileName" );
RtlInitUnicodeString(&sZwReadVirtualMemory, L"NtReadVirtualMemory");
RtlInitUnicodeString(&routineName, L"ZwQueryInformationProcess" );
RtlInitUnicodeString(&usDriverName, L"\\Device\\SCHiMDev");
RtlInitUnicodeString(&usDosDeviceName, L"\\DosDevices\\SCHiMDev");
NtStatus = IoCreateDevice(pDriverObject, 0, &usDriverName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObject);
if(NtStatus == STATUS_SUCCESS){
for(uiIndex = 0; uiIndex < IRP_MJ_MAXIMUM_FUNCTION; uiIndex++)
pDriverObject->MajorFunction[uiIndex] = UnSupportedFunction;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = Close;
pDriverObject->MajorFunction[IRP_MJ_CREATE] = Create;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoControl;
pDriverObject->MajorFunction[IRP_MJ_READ] = ReadNeither;
pDriverObject->MajorFunction[IRP_MJ_WRITE] = USE_WRITE_FUNCTION;
pDriverObject->DriverUnload = Unload;
pDeviceObject->Flags |= IO_TYPE;
pDeviceObject->Flags &= (~DO_DEVICE_INITIALIZING);
IoCreateSymbolicLink(&usDosDeviceName, &usDriverName);
}
gGetProcessImageFileName = (GET_PROCESS_IMAGE_NAME) MmGetSystemRoutineAddress( &sPsGetProcessImageFileName );
gZwQueryprocess = (QUERY_INFO_PROCESS) MmGetSystemRoutineAddress(&routineName);
gZwReadVirtualMemory = (ZWREADVIRTUAL)MmGetSystemRoutineAddress(&sZwReadVirtualMemory);
return NtStatus;
}
/**********************************************************************
*
* Unload
*
* This is an optional unload function which is called when the
* driver is unloaded.
*
**********************************************************************/
VOID Unload(PDRIVER_OBJECT DriverObject){
UNICODE_STRING usDosDeviceName;
DbgPrint("Unload Called \r\n");
RtlInitUnicodeString(&usDosDeviceName, L"\\DosDevices\\SCHiMDev");
IoDeleteSymbolicLink(&usDosDeviceName);
if( IsLoggerOn == TRUE){
PsSetCreateProcessNotifyRoutine(&INIT_ProcessCallback, TRUE);
}
IoDeleteDevice(DriverObject->DeviceObject);
}
NTSTATUS Create(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
DbgPrint("Create Called \r\n");
return NtStatus;
}
/**********************************************************************
*
* Close
*
* This is called when an instance of this driver is closed (CloseHandle)
*
**********************************************************************/
NTSTATUS Close(PDEVICE_OBJECT DeviceObject, PIRP Irp){
NTSTATUS NtStatus = STATUS_SUCCESS;
DbgPrint("Close Called \r\n");
return NtStatus;
}
/**********************************************************************
*
* IoControl
*
* This is called when an IOCTL is issued on the device handle (DeviceIoControl)
*
**********************************************************************/
NTSTATUS IoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
DbgPrint("IoControl Called \r\n");
return NtStatus;
}
/**********************************************************************
*
* Read
*
* This is called when a read is issued on the device handle (ReadFile/ReadFileEx)
*
**********************************************************************/
NTSTATUS Read(PDEVICE_OBJECT DeviceObject, PIRP Irp){
NTSTATUS NtStatus = STATUS_SUCCESS;
DbgPrint("Read Called \r\n");
return NtStatus;
}
/**********************************************************************
*
* WriteNeither
*
* This is called when a write is issued on the device handle (WriteFile/WriteFileEx)
*
* This version uses Neither buffered or direct I/O. User mode memory is
* read directly.
*
**********************************************************************/
NTSTATUS WriteNeither(PDEVICE_OBJECT DeviceObject, PIRP Irp){
NTSTATUS NtStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION pIoStackIrp = NULL;
PCHAR pWriteDataBuffer;
PULONG pLongPointer;
unsigned int uii = 0;
PCHAR Buffer[5];
PCHAR ARG_START_LOG = "PROC_LOG_START";
PCHAR ARG_STOP_LOG = "PROC_LOG_STOP";
PCHAR ARG_PAYLOAD_INCOMMING = "PAYLOAD_SET";
PCHAR ARG_TARGET_INCOMMING = "TARGET_SET";
PCHAR ARG_TARGET_DUMP_ADDRESS = "DUMP_DATA_SET";
PCHAR ARG_DUMP_WHEN_POSSIBLE = "DUMP_DUMP";
PCHAR ARG_RESET = "ERR_RESET";
pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);
if(pIoStackIrp){
__try {
if(IsSupplyDumpData != TRUE){
ProbeForRead(Irp->UserBuffer, pIoStackIrp->Parameters.Write.Length, TYPE_ALIGNMENT(char));
pWriteDataBuffer = Irp->UserBuffer;
} else {
ProbeForRead(Irp->UserBuffer, pIoStackIrp->Parameters.Write.Length, TYPE_ALIGNMENT(ULONG));
pLongPointer = Irp->UserBuffer;
}
if( pWriteDataBuffer){
if(IsPayloadCall == TRUE){
IsPayloadCall = FALSE;
}else if(IsSupplyDumpData == TRUE){
IsSupplyDumpData = FALSE;
AddressOfDump = pLongPointer[0];
SizeOfDump = pLongPointer[1];
DbgPrint("Address: 0x%x\nSize: 0x%x\n", AddressOfDump, SizeOfDump);
}else if(IsRegisterTarget == TRUE) {
IsRegisterTarget = FALSE;
for(uii = 0; uii != pIoStackIrp->Parameters.Write.Length; uii++){
Target[uii] = pWriteDataBuffer[uii];
}
}else if(IsStringTerminated( pWriteDataBuffer, pIoStackIrp->Parameters.Write.Length)){
if( CompareStrings(pWriteDataBuffer, ARG_START_LOG) == TRUE){
NtStatus = PsSetCreateProcessNotifyRoutine(&INIT_ProcessCallback, FALSE);
IsLoggerOn = TRUE;
}
if( CompareStrings(pWriteDataBuffer, ARG_RESET) == TRUE){
if( IsLoggerOn == TRUE){
PsSetCreateProcessNotifyRoutine(&INIT_ProcessCallback, TRUE);
}
if( IsDumpDumped == TRUE){
ExFreePool(TargetDump);
}
IsLoggerOn = FALSE;
Print = FALSE;
IsPayloadCall = FALSE;
IsRegisterTarget = FALSE;
IsSupplyDumpData = FALSE;
IsDumpWhenPossible = FALSE;
IsDumpDumped = FALSE;
ClearBuffer((PCHAR)&Buffer1[0], sizeof(Buffer1));
ClearBuffer((PCHAR)&Target[0], sizeof(Target));
AddressOfDump = 0;
SizeOfDump = 0;
hThreadHandle = 0;
hgtPid = 0;
}
if( CompareStrings(pWriteDataBuffer, ARG_DUMP_WHEN_POSSIBLE) == TRUE){
IsDumpWhenPossible = TRUE;
}
if( CompareStrings(pWriteDataBuffer, ARG_TARGET_DUMP_ADDRESS) == TRUE){
IsSupplyDumpData = TRUE;
}
if( CompareStrings(pWriteDataBuffer, ARG_STOP_LOG) == TRUE){
PsSetCreateProcessNotifyRoutine(&INIT_ProcessCallback, TRUE);
IsLoggerOn = FALSE;
}
if( CompareStrings (pWriteDataBuffer, ARG_TARGET_INCOMMING) == TRUE){
IsRegisterTarget = TRUE;
}
if( CompareStrings(pWriteDataBuffer, ARG_PAYLOAD_INCOMMING) == TRUE){
IsPayloadCall = TRUE;
}
}
}
} __except( EXCEPTION_EXECUTE_HANDLER ) {
DbgPrint("Exception occured in the write function");
NtStatus = GetExceptionCode();
}
}
return NtStatus;
}
NTSTATUS ReadNeither(PDEVICE_OBJECT DeviceObject, PIRP Irp){ // for incomming reads
NTSTATUS NtStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION pIoStackIrp = NULL;
unsigned int FindNextDump = 0;
PCHAR pWriteDataBuffer;
UNICODE_STRING NotEnoughSpace;
RtlInitUnicodeString(&NotEnoughSpace, L"Nes");
/*
* Each time the IRP is passed down the driver stack a new stack location is added
* specifying certain parameters for the IRP to the driver.
*/
pIoStackIrp = IoGetCurrentIrpStackLocation(Irp);
try{
ProbeForWrite(Irp->UserBuffer, pIoStackIrp->Parameters.Read.Length, TYPE_ALIGNMENT(char));
pWriteDataBuffer = Irp->UserBuffer;
if(pWriteDataBuffer){
if( Print == TRUE){
memcpy((PVOID)pWriteDataBuffer, (PVOID)&Buffer1[0], 200);
ClearBuffer((PCHAR)&Buffer1[0], 200);
Print = FALSE;
}
if( IsDumpWhenPossible == TRUE ){
if( IsDumpDumped == TRUE ){
memcpy((PVOID)pWriteDataBuffer, (PVOID)TargetDump, pIoStackIrp->Parameters.Read.Length);
ExFreePool(TargetDump);
IsDumpWhenPossible = FALSE;
IsDumpDumped = FALSE;
}
}
DbgPrint("Read Called! \r\n");
}
} __except( EXCEPTION_EXECUTE_HANDLER ) {
DbgPrint("Something went wrong inside the read function! Print: %d\r\n",Print );
NtStatus = GetExceptionCode();
}
return NtStatus;
}
/**********************************************************************
*
* UnSupportedFunction
*
* This is called when a major function is issued that isn't supported.
*
**********************************************************************/
NTSTATUS UnSupportedFunction(PDEVICE_OBJECT DeviceObject, PIRP Irp){
NTSTATUS NtStatus = STATUS_NOT_SUPPORTED;
DbgPrint("UnSupportedFunction Called \r\n");
return NtStatus;
}
/**********************************************************************
*
* IsStringTerminated
*
* Simple function to determine a string is NULL terminated.
*
**** We could validate also the characters in the string are printable! ***
*
**********************************************************************/
BOOLEAN CompareStrings(PCHAR pString1, PCHAR pString2){
unsigned int uiIndex = 0;
unsigned int uiLength1 = 0;
unsigned int uiLength2 = 0;
uiLength1 = StrLenKernelSafe(pString1);
uiLength2 = StrLenKernelSafe(pString2);
if(uiLength1 != uiLength2){
DbgPrint("Invailid length! %d != %d\n", uiLength1, uiLength2);
return FALSE;
}
while( uiLength1 > uiIndex ){
if(pString1[uiIndex] != pString2[uiIndex]){
DbgPrint("Strings don't match!\n");
return FALSE;
} else {
uiIndex++;
}
}
return TRUE;
}
unsigned int StrLenKernelSafe(PCHAR pString){
unsigned int uiIndex = 0;
__try{
while(pString != NULL && pString[uiIndex] != '\0'){
uiIndex++;
}
} __except( EXCEPTION_EXECUTE_HANDLER ) {
DbgPrint("StrLenKernelSafe exception\n");
}
return uiIndex;
}
BOOLEAN IsStringTerminated(PCHAR pString, unsigned int uiLength){
BOOLEAN bStringIsTerminated = FALSE;
unsigned int uiIndex = 0;
while(uiIndex < uiLength && bStringIsTerminated == FALSE)
{
if(pString[uiIndex] == '\0')
{
bStringIsTerminated = TRUE;
}
else
{
uiIndex++;
}
}
return bStringIsTerminated;
}
VOID INIT_ProcessCallback( IN HANDLE hParentId, IN HANDLE hProcessId, IN BOOLEAN bCreate) {
PEPROCESS pParentEP = NULL;
PEPROCESS pChildEP = NULL;
NTSTATUS Status = STATUS_SUCCESS;
ACCESS_MASK DesiredAccess = PROCESS_ALL_ACCESS;
OBJECT_ATTRIBUTES ObjectAttributes;
InitializeObjectAttributes (&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
/********************************
PsLookupProcessByProcessId(
__in HANDLE ProcessId,
__out PEPROCESS *Process
*******************************/
__try{
PsLookupProcessByProcessId(hParentId, &pParentEP);
PsLookupProcessByProcessId(hProcessId, &pChildEP);
} __except( EXCEPTION_EXECUTE_HANDLER ) {
ObDereferenceObject((PVOID)pParentEP);
ObDereferenceObject((PVOID)pChildEP);
DbgPrint("Something went very wrong!\n");
return;
}
if( gGetProcessImageFileName != NULL ){
PCHAR pParentImageName = gGetProcessImageFileName(pParentEP);
PCHAR pChildImageName = gGetProcessImageFileName(pChildEP);
__try{
if(Target != NULL){
if( CompareStrings((PCHAR)&Target[0], pChildImageName) == TRUE){
if(bCreate == 1){
hgtPid = hProcessId;
Status = PsCreateSystemThread(&hThreadHandle, DesiredAccess, &ObjectAttributes, NULL, NULL, (PKSTART_ROUTINE)&ModuleDumperThread, NULL);
if(Status != STATUS_SUCCESS){
DbgPrint("PsCreateSystemThread failed\n");
DbgPrint("NtStatus: 0x%x\n", Status);
}
}
}
}else if( pParentImageName != NULL && pChildImageName != NULL ) {
if(bCreate == 1){
DbgPrint("%s With pid[%x] created process %s with pid[%x]", pParentImageName, hParentId, pChildImageName, hProcessId);
RtlStringCbPrintfA((PCHAR)&Buffer1[0], sizeof("%s With pid[%x] created process %s with pid[%x]\n")+StrLenKernelSafe(pChildImageName)+StrLenKernelSafe(pParentImageName), "%s With pid[%x] created process %s with pid[%x]\n", pParentImageName, hParentId, pChildImageName, hProcessId);
Print = TRUE;
} else {
DbgPrint("%s With pid[%x] terminated process %s with pid[%x]", pParentImageName, hParentId, pChildImageName, hProcessId);
RtlStringCbPrintfA((PCHAR)&Buffer1[0], sizeof("%s With pid[%x] terminated process %s with pid[%x]\n")+StrLenKernelSafe(pChildImageName)+StrLenKernelSafe(pParentImageName), "%s With pid[%x] terminated process %s with pid[%x]\n", pParentImageName, hParentId, pChildImageName, hProcessId);
Print = TRUE;
}
}
}__except( EXCEPTION_EXECUTE_HANDLER ) {
ObDereferenceObject((PVOID)pParentEP);
ObDereferenceObject((PVOID)pChildEP);
DbgPrint("Exception at formatstring\n");
return;
}
}
ObDereferenceObject((PVOID)pParentEP);
ObDereferenceObject((PVOID)pChildEP);
return;
}
void ClearBuffer(PCHAR Buffer, unsigned int Length){
unsigned int uii = 0;
__try{
for(uii; uii != Length; uii++){
Buffer[uii] = '\0';
}
}__except( EXCEPTION_EXECUTE_HANDLER ) {
DbgPrint("Exception at ClearBuffer\n");
return;
}
return;
}
void Timeout(INT64 Timout){
INT64 MyTimeout = 0;
for( MyTimeout = 0; MyTimeout != Timout; MyTimeout++){}
return;
}
void Dump(PEPROCESS ep){
TargetDump = (PCHAR) ExAllocatePoolWithTag(NonPagedPool,SizeOfDump,"brak");
if(TargetDump == NULL){
IsDumpDumped = FALSE;
return;
}
KeAttachProcess(ep);
__try{
memcpy((PVOID)TargetDump, (PVOID)AddressOfDump, SizeOfDump);
}__except( EXCEPTION_EXECUTE_HANDLER ) {
DbgPrint("Exception while copying the dump\n");
IsDumpDumped = FALSE;
}
IsDumpDumped = TRUE;
KeDetachProcess();
return;
}
void ModuleDumperThread(){
NTSTATUS Status = STATUS_SUCCESS;
HANDLE hProcessHandle = NULL;
PLIST_ENTRY Next;
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
CLIENT_ID clientID;
ACCESS_MASK DesiredAccess = PROCESS_ALL_ACCESS;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hProcessId = hgtPid;
PROCESS_BASIC_INFORMATION BasicInfoReal;
ULONG SizeReturned;
PEPROCESS ep = NULL;
unsigned int Index = 0;
InitializeObjectAttributes (&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
clientID.UniqueProcess = hProcessId;
clientID.UniqueThread = NULL;
__try{
Status = ZwOpenProcess(&hProcessHandle, DesiredAccess, &ObjectAttributes, &clientID);
if(Status != STATUS_SUCCESS){
DbgPrint("Failed to open process\n");
DbgPrint("NtStatus: 0x%x", Status);
return;
}
Status = gZwQueryprocess(hProcessHandle, ProcessBasicInformation, (PVOID)&BasicInfoReal, sizeof(PROCESS_BASIC_INFORMATION), &SizeReturned);
if(Status != STATUS_SUCCESS){
DbgPrint("gZwQueryprocess failed\n");
DbgPrint("Size returned: 0x%x\nNtStatus: 0x%x\n", SizeReturned, Status);
ZwClose(hProcessHandle);
return;
}
Status = PsLookupProcessByProcessId(hProcessId, &ep);
if(Status != STATUS_SUCCESS){
DbgPrint("PsLookupProcessByProcessId failed\n");
DbgPrint("NtStatus: 0x%x\n", Status);
ZwClose(hProcessHandle);
return;
}
while(IsDumpWhenPossible!=TRUE){
Timeout((INT64)0x3FFFFFF); // wait until the process is fully loaded
}
if(IsDumpWhenPossible == TRUE){
Dump(ep);
}
/*
KeAttachProcess(ep);
__try{
DbgPrint("ImageBaseAddress of notepad.exe: 0x%x\n", BasicInfoReal.PebBaseAddress->ImageBaseAddress);
Next = BasicInfoReal.PebBaseAddress->Ldr->InLoadOrderModuleList.Blink;
LdrDataTableEntry = CONTAINING_RECORD( Next, LDR_DATA_TABLE_ENTRY, LoadOrder);
for(Index = 0; Index != 17; Index++){
DbgPrint("%d: ImageBase of %wZ in Notepad.exe: 0x%x\n", Index, &(LdrDataTableEntry->ModuleName), LdrDataTableEntry->ModuleBaseAddress);
Next = Next->Blink;
LdrDataTableEntry = CONTAINING_RECORD(Next, LDR_DATA_TABLE_ENTRY, LoadOrder);
}
}__except( EXCEPTION_EXECUTE_HANDLER ) {
DbgPrint("Exception while accessing the LDR\n");
}
KeDetachProcess();
*/
}__except( EXCEPTION_EXECUTE_HANDLER ) {
DbgPrint("Exception in ModuleDumper\n");
}
ObDereferenceObject((PVOID)ep);
ZwClose(hProcessHandle);
return;
}
Code:
/*
*
* File Name:
*
* disasm.c
*
* Summary:
*
* This file was created to be included within a 'disassembler' project for PE
* image files running on x86 and x86-compatible processors.
*
* File contains functions for disassembling IA32 binary instructions
*
*
*
* Copyright (C) 2004, Isaac Sigasa [isigasa@ananzi.co.za]
* All Rights Reserved
*
*
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
*/
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include "Disasm.h"
extern InstructionTemplate _11OpcodeExtensions[0x10][0x8][0x3];
extern InstructionTemplate _1ByteOpcode[0x10][0x10];
extern InstructionTemplate _2ByteOpcode[0x10][0x10][0x5];
extern InstructionTemplate MemOpcodeExtensions[0x10][0x8][0x3];
extern InstructionTemplate FPUModRMReg[0x8][0x8];
extern InstructionTemplate FPUModRMFullD8[0x4][0x10];
extern InstructionTemplate FPUModRMFullD9[0x4][0x10];
extern InstructionTemplate FPUModRMFullDA[0x4][0x10];
extern InstructionTemplate FPUModRMFullDB[0x4][0x10];
extern InstructionTemplate FPUModRMFullDC[0x4][0x10];
extern InstructionTemplate FPUModRMFullDD[0x4][0x10];
extern InstructionTemplate FPUModRMFullDE[0x4][0x10];
extern InstructionTemplate FPUModRMFullDF[0x4][0x10];
int IsIA32InstructionPrefix(unsigned char c)
{
switch(c)
{
case 0xF0:
case 0xF2:
case 0xF3:
case 0x2E:
case 0x36:
case 0x3E:
case 0x26:
case 0x64:
case 0x65:
case 0x66:
case 0x67:
return 1;
};
return 0;
};
void FetchOperandDescriptors(const InstructionTemplate *pInstructionTemplate, IA32InstructionDecode *pIA32Decode)
{
int iCol = 0, iTemp = 0;
if(pInstructionTemplate->strOperandsDescr == N)
return;
if(!strlen(pIA32Decode->SIA32InstructionDescription.strOperandA))
{
while((pInstructionTemplate->strOperandsDescr[iCol] != 0) && (pInstructionTemplate->strOperandsDescr[iCol] != ','))
{
pIA32Decode->SIA32InstructionDescription.strOperandA[iTemp++] = pInstructionTemplate->strOperandsDescr[iCol];
iCol++;
}
}
else
iCol = 0;
iTemp = 0;
if(pInstructionTemplate->strOperandsDescr[iCol] == ',')
iCol++;
if(!strlen(pIA32Decode->SIA32InstructionDescription.strOperandB))
{
while((pInstructionTemplate->strOperandsDescr[iCol] != 0) && (pInstructionTemplate->strOperandsDescr[iCol] != ','))
{
pIA32Decode->SIA32InstructionDescription.strOperandB[iTemp++] = pInstructionTemplate->strOperandsDescr[iCol];
iCol++;
};
}
else
iCol = 0;
iTemp = 0;
if(pInstructionTemplate->strOperandsDescr[iCol] == ',')
iCol++;
if(!strlen(pIA32Decode->SIA32InstructionDescription.strOperandC))
while((pInstructionTemplate->strOperandsDescr[iCol] != 0) && (pInstructionTemplate->strOperandsDescr[iCol] != ','))
{
pIA32Decode->SIA32InstructionDescription.strOperandC[iTemp++] = pInstructionTemplate->strOperandsDescr[iCol];
iCol++;
};
};
unsigned char GetSegmentOverride(IA32InstructionDecode *pIA32Decode)
{
int i;
char strSegOverrides[] = {0x2E,0x36,0x3E,0x26,0x64,0x65,0};
for(i = 0; i < pIA32Decode->SIA32InstructionHelper.cbRawPrefixes; i++)
if(strchr(strSegOverrides,pIA32Decode->SIA32RawInstruction.caRawPrefixes[i]))
return pIA32Decode->SIA32RawInstruction.caRawPrefixes[i];
return 0;
};
void GetSegmentOverrideStr(unsigned char sreg, char*strBuffer, int cbBuffer)
{
ZeroMemory(strBuffer,cbBuffer);
switch(sreg)
{
case 0x2E:
strncpy(strBuffer,"cs",cbBuffer);
break;
case 0x36:
strncpy(strBuffer,"ss",cbBuffer);
break;
case 0x3E:
strncpy(strBuffer,"ds",cbBuffer);
break;
case 0x26:
strncpy(strBuffer,"es",cbBuffer);
break;
case 0x64:
strncpy(strBuffer,"fs",cbBuffer);
break;
case 0x65:
strncpy(strBuffer,"gs",cbBuffer);
break;
};
};
int FetchPrefixes(const unsigned char *pStart, IA32InstructionDecode *pIA32Decode)
{
int i;
ZeroMemory(pIA32Decode->SIA32InstructionDescription.strPrefix,sizeof(pIA32Decode->SIA32InstructionDescription.strPrefix));
ZeroMemory(pIA32Decode->SIA32RawInstruction.caRawPrefixes,sizeof(pIA32Decode->SIA32RawInstruction.caRawPrefixes));
pIA32Decode->SIA32InstructionHelper.cbRawPrefixes = 0;
strcat(pIA32Decode->SIA32InstructionDescription.strPrefix,"");
// Instruction prefixes can only be up to four, so let's probe for at most four times
for(i = 0; i < 4; i++)
{
switch(pStart[i])
{
case 0xF0:
if(strlen(pIA32Decode->SIA32InstructionDescription.strPrefix))
strcat(pIA32Decode->SIA32InstructionDescription.strPrefix," lock");
else
strcat(pIA32Decode->SIA32InstructionDescription.strPrefix,"lock");
break;
case 0xF2:
if(strlen(pIA32Decode->SIA32InstructionDescription.strPrefix))
strcat(pIA32Decode->SIA32InstructionDescription.strPrefix," repne");
else
strcat(pIA32Decode->SIA32InstructionDescription.strPrefix,"repne");
break;
case 0xF3:
if(strlen(pIA32Decode->SIA32InstructionDescription.strPrefix))
strcat(pIA32Decode->SIA32InstructionDescription.strPrefix," rep");
else
strcat(pIA32Decode->SIA32InstructionDescription.strPrefix,"rep");
break;
case 0x2E:
case 0x36:
case 0x3E:
case 0x26:
case 0x64:
case 0x65:
case 0x66:
case 0x67:
break;
default:
return i;
};
pIA32Decode->SIA32RawInstruction.caRawPrefixes[i] = pStart[i];
pIA32Decode->SIA32InstructionHelper.cbRawPrefixes++;
};
return i;
};
int IA32InstructionPrefixExists(unsigned char cPrefix, IA32InstructionDecode *pIA32Decode)
{
int i;
for(i = 0; i < pIA32Decode->SIA32InstructionHelper.cbRawPrefixes; i++)
if(pIA32Decode->SIA32RawInstruction.caRawPrefixes[i] == cPrefix)
return 1;
return 0;
};
int FetchFPUInstruction(IA32InstructionDecode *pIA32Decode)
{
unsigned char ModRM = pIA32Decode->SIA32RawInstruction.ModRM;
int iRow;
int iCol;
InstructionTemplate *pInstructionTemplate = NULL;
if((ModRM >= 0) && (ModRM <= 0xBF))
{
iRow = pIA32Decode->SIA32RawInstruction.URawOpcode.cByteRawOpcode - 0xD8;
iCol = (ModRM & 0x38) >> 3;
pInstructionTemplate = &FPUModRMReg[iRow][iCol];
if(pInstructionTemplate->strOpcode == N)
return 1;
strcpy(pIA32Decode->SIA32InstructionDescription.strOpcode,pInstructionTemplate->strOpcode);
FetchOperandDescriptors(pInstructionTemplate,pIA32Decode);
return 1;
};
iRow = (ModRM & 0xF0) >> 4;
iRow -= 0x0B + 1;
iCol = ModRM & 0x0F;
switch(pIA32Decode->SIA32RawInstruction.URawOpcode.cByteRawOpcode)
{
case 0xD8:
pInstructionTemplate = &FPUModRMFullD8[iRow][iCol];
break;
case 0xD9:
pInstructionTemplate = &FPUModRMFullD9[iRow][iCol];
break;
case 0xDA:
pInstructionTemplate = &FPUModRMFullDA[iRow][iCol];
break;
case 0xDB:
pInstructionTemplate = &FPUModRMFullDB[iRow][iCol];
break;
case 0xDC:
pInstructionTemplate = &FPUModRMFullDC[iRow][iCol];
break;
case 0xDD:
pInstructionTemplate = &FPUModRMFullDD[iRow][iCol];
break;
case 0xDE:
pInstructionTemplate = &FPUModRMFullDE[iRow][iCol];
break;
case 0xDF:
pInstructionTemplate = &FPUModRMFullDF[iRow][iCol];
break;
};
if(((ModRM & 0xF0) >> 4) < 0x0B)
return 1;
iRow = (ModRM & 0xF0) >> 4;
iRow -= 0x0B + 1;
iCol = ModRM & 0x0F;
if(pInstructionTemplate->strOpcode == N)
return 1;
strcpy(pIA32Decode->SIA32InstructionDescription.strOpcode,pInstructionTemplate->strOpcode);
FetchOperandDescriptors(pInstructionTemplate,pIA32Decode);
return 1;
};
int FetchInstructionFrom1ByteOpcodeTable(const unsigned char *pStart,IA32InstructionDecode *pIA32Decode)
{
unsigned int iRow, iCol;
InstructionTemplate *pInstructionTemplate;
unsigned char ucTemp;
unsigned char ModRM;
char *pchr1;
char *pchr2;
char strTemp[64];
ucTemp = pIA32Decode->SIA32RawInstruction.URawOpcode.cByteRawOpcode = pStart[0];
pIA32Decode->SIA32InstructionHelper.cbRawOpcode = 1;
/* FPU encodings are in 1 byte opcode table and are running from 0xD8 to 0xDF
* Let's check if we have an FP instruction and deal with it
*/
if((ucTemp >= 0xD8) && (ucTemp <= 0xDF))
{
/* if it's an FP instruction - we have an ModRM byte */
ModRM = pIA32Decode->SIA32RawInstruction.ModRM = pStart[1];
pIA32Decode->SIA32InstructionHelper.boolModRMExists = 1;
FetchFPUInstruction(pIA32Decode);
return 1;
}
iRow = (unsigned int)(pStart[0] >> 4);
iCol = (unsigned int)(pStart[0] & 0x0F);
pInstructionTemplate = &_1ByteOpcode[iRow][iCol];
if(pInstructionTemplate->strOpcode == N)
return 1;
if(!strnicmp(pInstructionTemplate->strOpcode,"__G",strlen("__G")))
{
pIA32Decode->SIA32RawInstruction.ModRM = pStart[1];
pIA32Decode->SIA32InstructionHelper.boolModRMExists = 1;
pchr1 = pInstructionTemplate->strOpcode + strlen("__G");
ucTemp = (unsigned char)strtoul(pchr1,&pchr2,10);
if((ucTemp == 0) || (*pchr2 != 0))
return 0;
if((pIA32Decode->SIA32RawInstruction.ModRM & 0xC0) == 0xC0)
FetchInstructionFromOpcodeExtensionsTable(ucTemp,pStart,_11OpcodeExtensions,pIA32Decode);
else
FetchInstructionFromOpcodeExtensionsTable(ucTemp,pStart,MemOpcodeExtensions,pIA32Decode);
}
else
strcpy(pIA32Decode->SIA32InstructionDescription.strOpcode,pInstructionTemplate->strOpcode);
FetchOperandDescriptors(pInstructionTemplate,pIA32Decode);
if(strchr(pIA32Decode->SIA32InstructionDescription.strOperandA,'/'))
if(!strcmp(pIA32Decode->SIA32InstructionDescription.strOpcode,"test"))
{
/*
* layout of 0xF6 'test' instruction is violating the intergrity provided
* by the layout of opcode tables,
* so let's treat the 0xF6 opcode separately.
* we basically need to swap the operands
*
*/
strcpy(strTemp,pIA32Decode->SIA32InstructionDescription.strOperandA);
strcpy(pIA32Decode->SIA32InstructionDescription.strOperandA,pIA32Decode->SIA32InstructionDescription.strOperandB);
strcpy(pIA32Decode->SIA32InstructionDescription.strOperandB,strTemp);
}
if(strchr(pIA32Decode->SIA32InstructionDescription.strOperandA,'/'))
{
pchr1 = pIA32Decode->SIA32InstructionDescription.strOperandB;
while((*pchr1) && isupper(*pchr1))
pchr1++;
if(GetOperandTypeSize(pchr1) == 1)
{
pchr1 = strchr(pIA32Decode->SIA32InstructionDescription.strOperandA,'/');
if(pchr1)
*pchr1 = 0;
}
else
{
strcpy(strTemp,strchr(pIA32Decode->SIA32InstructionDescription.strOperandA,'/') + 1);
strcpy(pIA32Decode->SIA32InstructionDescription.strOperandA,strTemp);
}
}
if(strchr(pIA32Decode->SIA32InstructionDescription.strOperandB,'/'))
{
pchr1 = pIA32Decode->SIA32InstructionDescription.strOperandA;
while((*pchr1) && isupper(*pchr1))
pchr1++;
if(GetOperandTypeSize(pchr1) == 1)
{
pchr1 = strchr(pIA32Decode->SIA32InstructionDescription.strOperandB,'/');
if(pchr1)
*pchr1 = 0;
}
else
{
strcpy(strTemp,strchr(pIA32Decode->SIA32InstructionDescription.strOperandB,'/') + 1);
strcpy(pIA32Decode->SIA32InstructionDescription.strOperandB,strTemp);
}
}
return 1;
};
int FetchInstructionFrom2ByteOpcodeTable(const unsigned char *pStart,IA32InstructionDecode *pIA32Decode)
{
int iRow, iCol, i;
InstructionTemplate *pInstructionTemplate;
char *pchr1;
char *pchr2;
unsigned char ModRM;
unsigned char ucPrefix;
unsigned char ucTemp;
CopyMemory(pIA32Decode->SIA32RawInstruction.URawOpcode.ca2ByteRawOpcode,pStart,2);
pIA32Decode->SIA32InstructionHelper.cbRawOpcode = 2;
iRow = pStart[1] >> 4;
iCol = pStart[1] & 0x0F;
if(_2ByteOpcode[iRow][iCol][0].strOpcode == N)
return 1;
for(i = 0; i < 5; i++)
{
pInstructionTemplate = &_2ByteOpcode[iRow][iCol][i];
if(pInstructionTemplate->strOpcode == N)
return 1;
if(!strnicmp(pInstructionTemplate->strOpcode,"__G",strlen("__G")))
{
ModRM = pStart[pIA32Decode->SIA32InstructionHelper.cbRawPrefixes + 2];
pIA32Decode->SIA32RawInstruction.ModRM = ModRM;
pIA32Decode->SIA32InstructionHelper.boolModRMExists = 1;
pchr1 = pInstructionTemplate->strOpcode + strlen("__G");
ucTemp = (unsigned char)strtoul(pchr1,&pchr2,10);
if((ucTemp == 0) || (*pchr2 != 0))
return 0;
if((ModRM & 0xC0) == 0xC0)
FetchInstructionFromOpcodeExtensionsTable(ucTemp,pStart,_11OpcodeExtensions,pIA32Decode);
else
FetchInstructionFromOpcodeExtensionsTable(ucTemp,pStart,MemOpcodeExtensions,pIA32Decode);
FetchOperandDescriptors(pInstructionTemplate,pIA32Decode);
return 1;
};
if(strchr(pInstructionTemplate->strOpcode,'('))
{
pchr1 = strchr(pInstructionTemplate->strOpcode,'(') + 1;
ucPrefix = (unsigned char)strtoul(pchr1,&pchr2,0x10);
if((*pchr2 != ')') || (ucPrefix == 0))
return 0;
if(!IA32InstructionPrefixExists(ucPrefix,pIA32Decode))
return 1;
strcpy(pIA32Decode->SIA32InstructionDescription.strOpcode,pInstructionTemplate->strOpcode);
pchr1 = strchr(pIA32Decode->SIA32InstructionDescription.strOpcode,'(');
*pchr1 = 0;
FetchOperandDescriptors(pInstructionTemplate,pIA32Decode);
return 1;
};
if(strstr(pInstructionTemplate->strOpcode,"[M]")||strstr(pInstructionTemplate->strOpcode,"[R]"))
{
pIA32Decode->SIA32InstructionHelper.boolModRMExists = 1;
ModRM = pStart[pIA32Decode->SIA32InstructionHelper.cbRawPrefixes + 2];
pIA32Decode->SIA32RawInstruction.ModRM = ModRM;
if(strstr(pInstructionTemplate->strOpcode,"[R]"))
if((ModRM & 0xC0) != 0xC0)
return 1;
if(strstr(pInstructionTemplate->strOpcode,"[M]"))
if((ModRM & 0xC0) == 0xC0)
return 1;
strcpy(pIA32Decode->SIA32InstructionDescription.strOpcode,pInstructionTemplate->strOpcode);
pchr1 = strchr(pIA32Decode->SIA32InstructionDescription.strOpcode,'[');
*pchr1 = 0;
FetchOperandDescriptors(pInstructionTemplate,pIA32Decode);
return 1;
};
strcpy(pIA32Decode->SIA32InstructionDescription.strOpcode,pInstructionTemplate->strOpcode);
FetchOperandDescriptors(pInstructionTemplate,pIA32Decode);
};
return 1;
};
int GetInstructionLength(IA32InstructionDecode *pIA32Decode)
{
return pIA32Decode->SIA32InstructionHelper.boolModRMExists +
pIA32Decode->SIA32InstructionHelper.boolSIBExists +
pIA32Decode->SIA32InstructionHelper.cbRawDisplacement +
pIA32Decode->SIA32InstructionHelper.cbRawImmediate +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.cbRawPrefixes;
};
int FetchInstructionFromOpcodeExtensionsTable(unsigned const char ucEntry,const unsigned char* pStart,InstructionTemplate OpcodeExtensions[0x10][0x8][0x3],IA32InstructionDecode *pIA32Decode)
{
unsigned char ModRM;
int i, iCol;
const int iRow = ucEntry - 1;
InstructionTemplate *pInstructionTemplate;
char *pchr1;
char *pchr2;
unsigned char ucPrefix;
unsigned char ucTemp;
/* In case we forgot to do some crucial steps somewhere - let's revisit the decode */
if(!pIA32Decode->SIA32InstructionHelper.boolModRMExists)
{
pIA32Decode->SIA32InstructionHelper.boolModRMExists = 1;
if(pStart[pIA32Decode->SIA32InstructionHelper.cbRawPrefixes] == 0x0F)
pIA32Decode->SIA32RawInstruction.ModRM = pStart[pIA32Decode->SIA32InstructionHelper.cbRawPrefixes + 2];
else
pIA32Decode->SIA32RawInstruction.ModRM = pStart[pIA32Decode->SIA32InstructionHelper.cbRawPrefixes + 1];
};
ModRM = pIA32Decode->SIA32RawInstruction.ModRM;
iCol = (ModRM & 0x38) >> 3;
pInstructionTemplate = &OpcodeExtensions[iRow][iCol][0];
if(pInstructionTemplate->strOpcode == N)
return 1;
for(i = 0; i < 3; i++)
{
pInstructionTemplate = &OpcodeExtensions[iRow][iCol][i];
if(pInstructionTemplate->strOpcode == N)
return 1;
if(strchr(pInstructionTemplate->strOpcode,'|'))
{
pchr1 = strchr(pInstructionTemplate->strOpcode,'|') + 1;
ucTemp = (unsigned char)strtoul(pchr1,&pchr2,10);
if(*pchr2 != '|')
return 0;
if((ucTemp & 0x07) == ucTemp)
{
strcpy(pIA32Decode->SIA32InstructionDescription.strOpcode,pInstructionTemplate->strOpcode);
*(pchr1 - 1) = 0;
FetchOperandDescriptors(pInstructionTemplate,pIA32Decode);
return 1;
}
};
if(strchr(pInstructionTemplate->strOpcode,'('))
{
pchr1 = strchr(pInstructionTemplate->strOpcode,'(') + 1;
ucPrefix = (unsigned char)strtoul(pchr1,&pchr2,0x10);
if((*pchr2 != ')') || (ucPrefix == 0))
return 0;
if(!IA32InstructionPrefixExists(ucPrefix,pIA32Decode))
return 1;
strcpy(pIA32Decode->SIA32InstructionDescription.strOpcode,pInstructionTemplate->strOpcode);
pchr1 = strchr(pIA32Decode->SIA32InstructionDescription.strOpcode,'(');
*pchr1 = 0;
FetchOperandDescriptors(pInstructionTemplate,pIA32Decode);
return 1;
};
strcpy(pIA32Decode->SIA32InstructionDescription.strOpcode,pInstructionTemplate->strOpcode);
FetchOperandDescriptors(pInstructionTemplate,pIA32Decode);
};
return 1;
};
int FetchOpcode(const char * pLoadAddress, const unsigned char* pStart, IA32InstructionDecode *pIA32Decode, DefaultOperationSizeAttrib DSize)
{
int iRet;
int i;
char strTemp[64];
strcpy(pIA32Decode->SIA32InstructionDescription.strOpcode,"???");
ZeroMemory(pIA32Decode->SIA32RawInstruction.URawOpcode.ca2ByteRawOpcode,sizeof(pIA32Decode->SIA32RawInstruction.URawOpcode.ca2ByteRawOpcode));
pIA32Decode->SIA32InstructionHelper.cbRawOpcode = 0;
iRet = FetchPrefixes(pStart,pIA32Decode);
pStart += iRet;
pLoadAddress += iRet;
if(IsIA32InstructionPrefix(pStart[0]))
return 1;
if(pStart[0] == 0x0F)
iRet = FetchInstructionFrom2ByteOpcodeTable(pStart, pIA32Decode);
else
iRet = FetchInstructionFrom1ByteOpcodeTable(pStart, pIA32Decode);
if(strchr(pIA32Decode->SIA32InstructionDescription.strOpcode,'/'))
{
strcpy(strTemp,pIA32Decode->SIA32InstructionDescription.strOpcode);
ZeroMemory(pIA32Decode->SIA32InstructionDescription.strOpcode,sizeof(pIA32Decode->SIA32InstructionDescription.strOpcode));
if(DSize == OpSize16)
{
if(!IA32InstructionPrefixExists(0x66,pIA32Decode))
/* take the opcode on the left of the '/' character */
for(i = 0; strTemp[i] != '/'; i++)
pIA32Decode->SIA32InstructionDescription.strOpcode[i] = strTemp[i];
else
strcpy(pIA32Decode->SIA32InstructionDescription.strOpcode,strchr(strTemp,'/') + 1);
}
else
{
if(IA32InstructionPrefixExists(0x66,pIA32Decode))
/* take the opcode on the left of the '/' character */
for(i = 0; strTemp[i] != '/'; i++)
pIA32Decode->SIA32InstructionDescription.strOpcode[i] = strTemp[i];
else
strcpy(pIA32Decode->SIA32InstructionDescription.strOpcode,strchr(strTemp,'/') + 1);
}
}
return iRet;
};
int isupperstr(const char *str)
{
while(*str)
if(islower(*str++))
return 0;
return 1;
};
int DecodeMMXRegisterRM(const unsigned char ModRM, char* strout)
{
if((ModRM & 0xC0) != 0xC0)
return 0;
sprintf(strout,"mm%d",ModRM & 0x07);
return 1;
};
int DecodeMMXRegisterReg(const unsigned char ModRM, char* strout)
{
return DecodeMMXRegisterRM((unsigned char)((ModRM >> 3) | 0xC0),strout);
};
int DecodeXMMRegisterRM(const unsigned char ModRM, char* strout)
{
return DecodeMMXRegisterRM(ModRM,strout);
};
int DecodeXMMRegisterReg(const unsigned char ModRM, char* strout)
{
return DecodeMMXRegisterReg(ModRM,strout);
};
int DecodeSegmentRegisterReg(const unsigned char ModRM, char* strout)
{
switch((ModRM & 0x38) >> 3)
{
case 0:
strcpy(strout,"es");
break;
case 1:
strcpy(strout,"cs");
break;
case 2:
strcpy(strout,"ss");
break;
case 3:
strcpy(strout,"ds");
break;
case 4:
strcpy(strout,"fs");
break;
case 5:
strcpy(strout,"gs");
break;
default:
strcpy(strout,"??");
break;
};
return 1;
}
int DecodeGPRegisterReg(const int size, const unsigned char ModRM, char* strout)
{
/* let's do some fooling-around here and redirect to the DecodeGPRegisterRM function */
return DecodeGPRegisterRM(size,(unsigned char)((ModRM >> 3) | 0xC0),strout);
};
int DecodeGPRegisterRM(const unsigned int size, const unsigned char ModRM, char* strout)
{
if((ModRM & 0xC0) != 0xC0)
return 0;
switch(size)
{
case 1:
switch(ModRM & 0x07)
{
case 0:
strcpy(strout,"al");
return 1;
case 1:
strcpy(strout,"cl");
return 1;
case 2:
strcpy(strout,"dl");
return 1;
case 3:
strcpy(strout,"bl");
return 1;
case 4:
strcpy(strout,"ah");
return 1;
case 5:
strcpy(strout,"ch");
return 1;
case 6:
strcpy(strout,"dh");
return 1;
case 7:
strcpy(strout,"bh");
return 1;
};
case 2:
switch(ModRM & 0x07)
{
case 0:
strcpy(strout,"ax");
return 1;
case 1:
strcpy(strout,"cx");
return 1;
case 2:
strcpy(strout,"dx");
return 1;
case 3:
strcpy(strout,"bx");
return 1;
case 4:
strcpy(strout,"sp");
return 1;
case 5:
strcpy(strout,"bp");
return 1;
case 6:
strcpy(strout,"si");
return 1;
case 7:
strcpy(strout,"di");
return 1;
};
case 4:
strout[0] = 'e';
return DecodeGPRegisterRM(2,ModRM,strout + 1);
};
return 0;
};
void GetMemoryOperandSizeStr(const char*strOpType, char *strOut,DefaultOperationSizeAttrib DSize, IA32InstructionDecode *pIA32Decode)
{
unsigned int uiTemp;
if(!strlen(strOpType))
return;
uiTemp = GetOperandTypeSize(strOpType + 1);
if(uiTemp & 0xFF000000)
{
if(DSize == OpSize16)
{
if(IA32InstructionPrefixExists(0x66,pIA32Decode))
uiTemp = (uiTemp & 0x0000FF00) >> 8;
else
uiTemp = (uiTemp & 0x000000FF);
}
else
{
if(IA32InstructionPrefixExists(0x66,pIA32Decode))
uiTemp = (uiTemp & 0x000000FF);
else
uiTemp = (uiTemp & 0x0000FF00) >> 8;
};
};
switch(uiTemp)
{
case 1:
strcpy(strOut,"byte ptr");
break;
case 2:
strcpy(strOut,"word ptr");
break;
case 4:
strcpy(strOut,"dword ptr");
break;
case 6:
strcpy(strOut,"fword ptr");
break;
case 8:
strcpy(strOut,"qword ptr");
break;
default:
strcpy(strOut,"");
}
};
int DecodeSingleRegisterOperand(DefaultOperationSizeAttrib DSize, int iOpIndex, IA32InstructionDecode *pIA32Decode)
{
char cAddressingMethod;
char *strOperandType;
char strOperandTemplate[16];
char *strOutput;
unsigned char ModRM;
unsigned int uiTemp = 0;
if(!pIA32Decode->SIA32InstructionHelper.boolModRMExists)
return 0;
ModRM = pIA32Decode->SIA32RawInstruction.ModRM;
if(!GetOutputBuffer(iOpIndex,&strOutput,pIA32Decode))
return 0;
strcpy(strOperandTemplate,strOutput);
if(!strlen(strOutput))
return 1;
cAddressingMethod = strOperandTemplate[0];
strOperandType = strOperandTemplate + 1;
if(strlen(strOperandType))
{
uiTemp = GetOperandTypeSize(strOperandType);
if(uiTemp & 0xFF000000)
{
/* register-size dependant on operand-size attribute */
if(DSize == OpSize16)
{
if(IA32InstructionPrefixExists(0x66,pIA32Decode))
uiTemp = (uiTemp & 0x0000FF00) >> 8;
else
uiTemp = (uiTemp & 0x000000FF);
}
else
{
if(IA32InstructionPrefixExists(0x66,pIA32Decode))
uiTemp = (uiTemp & 0x000000FF);
else
uiTemp = (uiTemp & 0x0000FF00) >> 8;
};
};
};
switch(cAddressingMethod)
{
case 'C':
/* The reg field of the ModR/M byte selects a control register */
switch((ModRM & 0x38)>>3)
{
case 0:
case 2:
case 3:
case 4:
sprintf(strOutput,"cr%d",(ModRM & 0x38)>>3);
return 1;
default:
return 0;
};
case 'D':
/* The reg field of the ModR/M byte selects a debug register */
switch((ModRM & 0x38)>>3)
{
case 0:
case 1:
case 2:
case 3:
case 6:
case 7:
sprintf(strOutput,"dr%d",(ModRM & 0x38)>>3);
return 1;
default:
return 0;
};
case 'E':
/* general-purpose register or memory, if register, use RM and Mod must be 11B */
if((ModRM & 0xC0) != 0xC0)
{
return 0;
};
switch(uiTemp)
{
case 1:
case 2:
case 4:
return DecodeGPRegisterRM(uiTemp,ModRM,strOutput);
default:
return 0;
};
case 'G':
/* general-purpose register using Reg field */
switch(uiTemp)
{
case 1:
case 2:
case 4:
return DecodeGPRegisterReg(uiTemp,ModRM,strOutput);
default:
return 0;
};
case 'P':
/* MMX register using Reg field */
return DecodeMMXRegisterReg(ModRM,strOutput);
case 'Q':
/* MMX registed using RM field */
if((ModRM & 0xC0) != 0xC0)
return 0;
return DecodeMMXRegisterRM(ModRM,strOutput);
case 'R':
if((ModRM & 0xC0) != 0xC0)
return 0;
switch(uiTemp)
{
case 1:
case 2:
case 4:
return DecodeGPRegisterRM(uiTemp,ModRM,strOutput);
default:
return 0;
};
case 'S':
/* The reg field of the ModR/M byte selects a segment register */
return DecodeSegmentRegisterReg(ModRM,strOutput);
case 'T':
sprintf(strOutput,"tr%d",(ModRM & 0x38) >> 3);
return 1;
case 'V':
return DecodeXMMRegisterReg(ModRM,strOutput);
case 'W':
if((ModRM & 0xC0) != 0xC0)
return 0;
return DecodeXMMRegisterRM(ModRM,strOutput);
};
return 0;
}
/*
* GetOperandTypeSize
* Returns value with HO byte set to 80 if the size is dependant on operand-size attribute
* in which case the HO byte of the LO word is set to actual size for 32-bit code, and the
* LO byte of the LO word is set to actual size for 16-bit code.
*
* If the operand size attribute doesn't matter - the HO byte of the return dword is set
* to 00 and the actual size of the operand is returned (on the LO byte)
*/
unsigned int GetOperandTypeSize(const char *strType)
{
unsigned int uTemp = 0;
if(strlen(strType) == 1)
{
switch(strType[0])
{
case 'a':
/* 4 or 16 bytes - depending on operand-size attribute */
uTemp = 0x80000804;
break;
case 'b':
/* byte, regardless of operand-size attribute */
uTemp = 0x00000001;
break;
case 'c':
/* byte or word depending on operand-size attribute */
uTemp = 0x80000201;
break;
case 'd':
/* dword regardless of operand-size attribute */
uTemp = 0x00000004;
break;
case 'p':
/* 32-bit or 48-bit depending of operand-size */
uTemp = 0x80000604;
break;
case 'q':
uTemp = 0x00000008;
break;
case 's':
uTemp = 0x00000006;
break;
case 'v':
uTemp = 0x80000402;
break;
case 'w':
uTemp = 0x00000002;
break;
default:
return 0;
}
}
else
{
if( !strcmp(strType,"dq")||
!strcmp(strType,"pd")||
!strcmp(strType,"ps")||
!strcmp(strType,"sd")||
!strcmp(strType,"ss"))
uTemp = 0x00000010;
else
{
if(!strcmp(strType,"pi"))
uTemp= 0x00000008;
else
{
return 0;
}
}
}
return uTemp;
};
int DecodeExplicitGPRegister(DefaultOperationSizeAttrib DSize, int iOpIndex, IA32InstructionDecode *pIA32Decode)
{
char *strOutput;
char strOperand[64];
if(!GetOutputBuffer(iOpIndex,&strOutput,pIA32Decode))
return 0;
if(!IsExplicitRegisterOperand(strOutput))
return 0;
strcpy(strOperand,strOutput);
if(DSize == OpSize32)
{
if(IA32InstructionPrefixExists(0x66,pIA32Decode))
strcpy(strOutput,strOperand + 1);
else
strcpy(strOutput,strOperand);
}
else
{
if(!IA32InstructionPrefixExists(0x66,pIA32Decode))
strcpy(strOutput,strOperand + 1);
else
strcpy(strOutput,strOperand);
};
strlwr(strOutput);
return 1;
};
int IsExplicitRegisterOperand(const char *strTest)
{
int i;
char *strRegs[] = {
"EAX","AX","AH","AL",
"EBX","BX","BH","BL",
"ECX","CX","CH","CL",
"EDX","DX","DH","DL",
"BP","EBP","SP","ESP","SI","ESI","DI","EDI",
"CS","SS","DS","ES","GS","FS"
};
if((strlen(strTest) == 2) && (isupperstr(strTest)))
for(i = 0; i < ARRAYSIZE(strRegs); i++)
if(!strcmp(strRegs[i],strTest))
return 1;
if((strlen(strTest) == 3) && (strTest[0] == 'e') && isupperstr(strTest + 1))
return IsExplicitRegisterOperand(strTest + 1);
return 0;
};
int DecodeMemoryOperand16(DefaultOperationSizeAttrib DSize, unsigned char *pStart, int iOpIndex, IA32InstructionDecode *pIA32Decode)
{
unsigned char ModRM;
unsigned char ucD8;
unsigned short usD16;
char *strOutput;
char cTemp = '+';
char strSegOverride[10] = "";
char strOpSize[20];
unsigned char ucSegOverride;
if(!pIA32Decode->SIA32InstructionHelper.boolModRMExists)
return 0;
if(!GetOutputBuffer(iOpIndex,&strOutput,pIA32Decode))
return 0;
GetMemoryOperandSizeStr(strOutput,strOpSize,DSize,pIA32Decode);
if(strlen(strOpSize))
strcat(strOpSize," ");
ModRM = pIA32Decode->SIA32RawInstruction.ModRM;
ucSegOverride = GetSegmentOverride(pIA32Decode);
GetSegmentOverrideStr(ucSegOverride,strSegOverride,sizeof(strSegOverride));
if(strlen(strSegOverride))
strcat(strSegOverride,":");
switch((ModRM & 0xC0) >> 6)
{
case 0:
switch(ModRM & 0x07)
{
case 0:
sprintf(strOutput,"%s%s[bx+si]",strOpSize,strSegOverride);
return 1;
case 1:
sprintf(strOutput,"%s%s[bx+di]",strOpSize,strSegOverride);
return 1;
case 2:
sprintf(strOutput,"%s%s[bp+si]",strOpSize,strSegOverride);
return 1;
case 3:
sprintf(strOutput,"%s%s[bp+di]",strOpSize,strSegOverride);
return 1;
case 4:
sprintf(strOutput,"%s%s[si]",strOpSize,strSegOverride);
return 1;
case 6:
/* we have a disp16 value */
pIA32Decode->SIA32InstructionHelper.cbRawDisplacement = 2;
CopyMemory(pIA32Decode->SIA32RawInstruction.URawDisplacement.ca2ByteRawDisplacement,
pStart + pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists,
2);
if(!strlen(strSegOverride))
strcpy(strSegOverride,"ds:");
sprintf(strOutput,"%s%s[0x%02X]",strOpSize,strSegOverride,(unsigned short*)pIA32Decode->SIA32RawInstruction.URawDisplacement.ca2ByteRawDisplacement);
return 1;
case 5:
sprintf(strOutput,"%s%s[di]",strOpSize,strSegOverride);
return 1;
case 7:
sprintf(strOutput,"%s%s[bx]",strOpSize,strSegOverride);
return 1;
};
case 1:
/* we have a disp8 value, needs to be sign-extended */
pIA32Decode->SIA32InstructionHelper.cbRawDisplacement = 1;
pIA32Decode->SIA32RawInstruction.URawDisplacement.cByteRawDisplacement =
pStart[pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists];
ucD8 = pIA32Decode->SIA32RawInstruction.URawDisplacement.cByteRawDisplacement;
if(ucD8 & 0x80)
{
cTemp = '-';
ucD8 = (unsigned char)(((short)-ucD8) & 0x00FF);
}
switch(ModRM & 0x07)
{
case 0:
sprintf(strOutput,"%s%s[bx+si%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
case 1:
sprintf(strOutput,"%s%s[bx+di%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
case 2:
sprintf(strOutput,"%s%s[bp+si%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
case 3:
sprintf(strOutput,"%s%s[bp+di%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
case 4:
sprintf(strOutput,"%s%s[si%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
case 5:
sprintf(strOutput,"%s%s[di%cx%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
case 6:
sprintf(strOutput,"%s%s[bp%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
case 7:
sprintf(strOutput,"%s%s[bx%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
};
case 2:
/* we have a disp16 value */
pIA32Decode->SIA32InstructionHelper.cbRawDisplacement = 2;
CopyMemory(pIA32Decode->SIA32RawInstruction.URawDisplacement.ca2ByteRawDisplacement,
pStart + pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists,
2);
usD16 = *(unsigned short*)pIA32Decode->SIA32RawInstruction.URawDisplacement.ca2ByteRawDisplacement;
switch(ModRM & 0x07)
{
case 0:
sprintf(strOutput,"%s%s[bx+si+0x%04X]",strOpSize,strSegOverride,usD16);
return 1;
case 1:
sprintf(strOutput,"%s%s[bx+di+0x%04X]",strOpSize,strSegOverride,usD16);
return 1;
case 2:
sprintf(strOutput,"%s%s[bp+si+0x%04X]",strOpSize,strSegOverride,usD16);
return 1;
case 3:
sprintf(strOutput,"%s%s[bp+di+0x%04X]",strOpSize,strSegOverride,usD16);
return 1;
case 4:
sprintf(strOutput,"%s%s[si+0x%04X]",strOpSize,strSegOverride,usD16);
return 1;
case 5:
sprintf(strOutput,"%s%s[di+0x%04X]",strOpSize,strSegOverride,usD16);
return 1;
case 6:
sprintf(strOutput,"%s%s[bp+0x%04X]",strOpSize,strSegOverride,usD16);
return 1;
case 7:
sprintf(strOutput,"%s%s[bx+0x%04X]",strOpSize,strSegOverride,usD16);
return 1;
};
};
return 0;
};
void GetSIBBase(unsigned char SIB, char *strBuffer, int cbBuffer)
{
ZeroMemory(strBuffer,cbBuffer);
switch(SIB & 0x7)
{
case 0:
strcpy(strBuffer,"eax");
return;
case 1:
strcpy(strBuffer,"ecx");
return;
case 2:
strcpy(strBuffer,"edx");
return;
case 3:
strcpy(strBuffer,"ebx");
return;
case 4:
strcpy(strBuffer,"esp");
return;
case 6:
strcpy(strBuffer,"esi");
return;
case 7:
strcpy(strBuffer,"edi");
return;
}
};
void GetSIBScaledIndex(unsigned char SIB, char *strBuffer, int cbBuffer)
{
unsigned char SS;
unsigned char Index;
unsigned char ucTemp;
SS = (unsigned char)((SIB & 0xC0) >> 6);
Index = (unsigned char)((SIB & 0x38) >> 3);
ZeroMemory(strBuffer,cbBuffer);
switch(SS)
{
case 0:
switch(Index)
{
case 0:
strncpy(strBuffer,"eax",cbBuffer);
return;
case 1:
strncpy(strBuffer,"ecx",cbBuffer);
return;
case 2:
strncpy(strBuffer,"edx",cbBuffer);
return;
case 3:
strncpy(strBuffer,"ebx",cbBuffer);
return;
case 5:
strncpy(strBuffer,"ebp",cbBuffer);
return;
case 6:
strncpy(strBuffer,"esi",cbBuffer);
return;
case 7:
strncpy(strBuffer,"edi",cbBuffer);
return;
};
return;
case 1:
case 2:
case 3:
/* play some trick - prepare and reuse code for case 0 above */
ucTemp = (unsigned char)(SIB & 0x3F);
GetSIBScaledIndex(ucTemp,strBuffer,cbBuffer);
if(Index != 4) /* otherwise we would get blank */
_snprintf(strBuffer + strlen(strBuffer),cbBuffer - strlen(strBuffer),"*%d",((unsigned char)1)<<SS);
return;
};
};
int DecodeMemory32SIB(DefaultOperationSizeAttrib DSize, unsigned char *pStart, int iOpIndex, IA32InstructionDecode *pIA32Decode)
{
unsigned char SIB;
unsigned char ModRM;
unsigned char ucD8;
unsigned int uiD32;
char strBase[64];
char strIndex[64];
char *strOutput;
char cTemp = '+';
char strOpSize[20];
if(!pIA32Decode->SIA32InstructionHelper.boolSIBExists)
return 0;
if(!pIA32Decode->SIA32InstructionHelper.boolModRMExists)
return 0;
ModRM = pIA32Decode->SIA32RawInstruction.ModRM;
SIB = pIA32Decode->SIA32RawInstruction.SIB;
if(!GetOutputBuffer(iOpIndex,&strOutput,pIA32Decode))
return 0;
GetMemoryOperandSizeStr(strOutput,strOpSize,DSize,pIA32Decode);
if(strlen(strOpSize))
strcat(strOpSize," ");
GetSIBBase(SIB,strBase,sizeof(strBase));
GetSIBScaledIndex(SIB,strIndex,sizeof(strIndex));
if(!strlen(strBase))
{
/* decode operand according to Mod field of ModRM byte */
switch(ModRM>>6)
{
case 0:
uiD32 = *((unsigned int*)(pStart +
pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists +
pIA32Decode->SIA32InstructionHelper.boolSIBExists));
*((unsigned int*)pIA32Decode->SIA32RawInstruction.URawDisplacement.ca4ByteRawDisplacement) = uiD32;
pIA32Decode->SIA32InstructionHelper.cbRawDisplacement = 4;
sprintf(strOutput,"%s[%s+0x%08X]",strOpSize,strIndex,uiD32);
return 1;
case 1:
ucD8 = pStart[pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists +
pIA32Decode->SIA32InstructionHelper.boolSIBExists];
pIA32Decode->SIA32RawInstruction.URawDisplacement.cByteRawDisplacement = ucD8;
pIA32Decode->SIA32InstructionHelper.cbRawDisplacement = 1;
if(ucD8 & 0x80)
{
cTemp = '-';
ucD8 = (unsigned char)(((short)-ucD8) & 0x00FF);
}
if(strlen(strIndex))
sprintf(strOutput,"%s[ebp+%s%c0x%02X]",strOpSize,strIndex,cTemp,ucD8);
else
sprintf(strOutput,"%s[ebp%c0x%02X]",strOpSize,cTemp,ucD8);
return 1;
case 2:
uiD32 = *((unsigned int*)(pStart +
pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists +
pIA32Decode->SIA32InstructionHelper.boolSIBExists));
*((unsigned int*)pIA32Decode->SIA32RawInstruction.URawDisplacement.ca4ByteRawDisplacement) = uiD32;
pIA32Decode->SIA32InstructionHelper.cbRawDisplacement = 4;
sprintf(strOutput,"%s[ebp+%s+0x%08X]",strOpSize,strIndex,uiD32);
return 1;
};
}
else
{
uiD32 = *((unsigned int*)pIA32Decode->SIA32RawInstruction.URawDisplacement.ca4ByteRawDisplacement);
ucD8 = pIA32Decode->SIA32RawInstruction.URawDisplacement.cByteRawDisplacement;
switch(pIA32Decode->SIA32InstructionHelper.cbRawDisplacement)
{
case 0:
if(strlen(strIndex))
sprintf(strOutput,"%s[%s+%s]",strOpSize,strBase,strIndex);
else
sprintf(strOutput,"%s[%s]",strOpSize,strBase);
return 1;
case 1:
if(ucD8 & 0x80)
{
cTemp = '-';
ucD8 = (unsigned char)(((short)-ucD8) & 0x00FF);
}
if(strlen(strIndex))
sprintf(strOutput,"%s[%s+%s%c0x%02X]",strOpSize,strBase,strIndex,cTemp,ucD8);
else
sprintf(strOutput,"%s[%s%c0x%02X]",strOpSize,strBase,cTemp,ucD8);
return 1;
case 4:
if(strlen(strIndex))
sprintf(strOutput,"%s[%s+%s+0x%08X]",strOpSize,strBase,strIndex,uiD32);
else
sprintf(strOutput,"%s[%s+0x%08X]",strOpSize,strBase,uiD32);
return 1;
default:
return 0;
}
}
return 0;
};
int DecodeMemoryOperand32(DefaultOperationSizeAttrib DSize, unsigned char *pStart, int iOpIndex, IA32InstructionDecode *pIA32Decode)
{
unsigned char ModRM;
unsigned char SIB;
unsigned char ucD8;
unsigned int uiD32;
char *strOutput;
char cTemp = '+';
char strSegOverride[10];
char strOpSize[20];
unsigned char ucSegOverride;
if(!pIA32Decode->SIA32InstructionHelper.boolModRMExists)
return 0;
if(!GetOutputBuffer(iOpIndex,&strOutput,pIA32Decode))
return 0;
GetMemoryOperandSizeStr(strOutput,strOpSize,DSize,pIA32Decode);
if(strlen(strOpSize))
strcat(strOpSize," ");
ModRM = pIA32Decode->SIA32RawInstruction.ModRM;
ucSegOverride = GetSegmentOverride(pIA32Decode);
GetSegmentOverrideStr(ucSegOverride,strSegOverride,sizeof(strSegOverride));
if(strlen(strSegOverride))
strcat(strSegOverride,":");
switch((ModRM & 0xC0) >> 6)
{
case 0:
switch(ModRM & 0x07)
{
case 0:
sprintf(strOutput,"%s%s[eax]",strOpSize,strSegOverride);
return 1;
case 1:
sprintf(strOutput,"%s%s[ecx]",strOpSize,strSegOverride);
return 1;
case 2:
sprintf(strOutput,"%s%s[edx]",strOpSize,strSegOverride);
return 1;
case 3:
sprintf(strOutput,"%s%s[ebx]",strOpSize,strSegOverride);
return 1;
case 4:
/* we got a SIB byte following the ModRM byte */
SIB = pStart[ pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists];
pIA32Decode->SIA32InstructionHelper.boolSIBExists = 1;
pIA32Decode->SIA32RawInstruction.SIB = SIB;
return DecodeMemory32SIB(DSize, pStart,iOpIndex,pIA32Decode);
case 5:
/* we just got a disp32 */
uiD32 = *((unsigned int*)(pStart + pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists));
if(!strlen(strSegOverride))
strcpy(strSegOverride,"ds:");
sprintf(strOutput,"%s%s[0x%08X]",strOpSize,strSegOverride,uiD32);
pIA32Decode->SIA32InstructionHelper.cbRawDisplacement = 4;
*((unsigned int*)pIA32Decode->SIA32RawInstruction.URawDisplacement.ca4ByteRawDisplacement) = uiD32;
return 1;
case 6:
sprintf(strOutput,"%s%s[esi]",strOpSize,strSegOverride);
return 1;
case 7:
sprintf(strOutput,"%s%s[edi]",strOpSize,strSegOverride);
return 1;
};
case 1:
/* we got a disp8, needs to sign-extended */
if((ModRM & 0x7) == 4)
ucD8 = pStart[ pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists + 1];
else
ucD8 = pStart[ pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists];
pIA32Decode->SIA32InstructionHelper.cbRawDisplacement = 1;
pIA32Decode->SIA32RawInstruction.URawDisplacement.cByteRawDisplacement = ucD8;
if(ucD8 & 0x80)
{
cTemp = '-';
ucD8 = (unsigned char)(((short)-ucD8) & 0x00FF);
}
switch(ModRM & 0x07)
{
case 0:
sprintf(strOutput,"%s%s[eax%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
case 1:
sprintf(strOutput,"%s%s[ecx%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
case 2:
sprintf(strOutput,"%s%s[edx%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
case 3:
sprintf(strOutput,"%s%s[ebx%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
case 4:
/* we got a SIB byte following the ModRM byte */
SIB = pStart[ pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists];
pIA32Decode->SIA32InstructionHelper.boolSIBExists = 1;
pIA32Decode->SIA32RawInstruction.SIB = SIB;
return DecodeMemory32SIB(DSize,pStart,iOpIndex,pIA32Decode);
case 5:
sprintf(strOutput,"%s%s[ebp%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
case 6:
sprintf(strOutput,"%s%s[esi%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
case 7:
sprintf(strOutput,"%s%s[edi%c0x%02X]",strOpSize,strSegOverride,cTemp,ucD8);
return 1;
};
case 2:
/* we got a disp32, assign it to the raw instruction, with possibility of SIB in mind */
if((ModRM & 0x7) == 4)
/* we have SIB */
uiD32 = *((unsigned int*)(pStart +pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists + 1));
else
uiD32 = *((unsigned int*)(pStart +pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists));
pIA32Decode->SIA32InstructionHelper.cbRawDisplacement = 4;
*((unsigned int*)pIA32Decode->SIA32RawInstruction.URawDisplacement.ca4ByteRawDisplacement) = uiD32;
switch(ModRM & 0x07)
{
case 0:
sprintf(strOutput,"%s%s[eax+0x%08X]",strOpSize,strSegOverride,uiD32);
return 1;
case 1:
sprintf(strOutput,"%s%s[ecx+0x%08X]",strOpSize,strSegOverride,uiD32);
return 1;
case 2:
sprintf(strOutput,"%s%s[edx+0x%08X]",strOpSize,strSegOverride,uiD32);
return 1;
case 3:
sprintf(strOutput,"%s%s[ebx+0x%08X]",strOpSize,strSegOverride,uiD32);
return 1;
case 4:
/* we got a SIB byte following the ModRM byte */
SIB = pStart[ pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists];
pIA32Decode->SIA32InstructionHelper.boolSIBExists = 1;
pIA32Decode->SIA32RawInstruction.SIB = SIB;
return DecodeMemory32SIB(DSize,pStart,iOpIndex,pIA32Decode);
case 5:
sprintf(strOutput,"%s%s[ebp+0x%08X]",strOpSize,strSegOverride,uiD32);
return 1;
case 6:
sprintf(strOutput,"%s%s[esi+0x%08X]",strOpSize,strSegOverride,uiD32);
return 1;
case 7:
sprintf(strOutput,"%s%s[edi+0x%08X]",strOpSize,strSegOverride,uiD32);
return 1;
};
};
return 0;
}
int DecodeMemoryOperand(unsigned char *pStart, DefaultOperationSizeAttrib DSize, int iOpIndex, IA32InstructionDecode *pIA32Decode)
{
int iRet;
/* if the instruction has an address-size attribute we use non-default addressing mode */
if(DSize == OpSize32)
{
if(IA32InstructionPrefixExists(0x67,pIA32Decode))
iRet = DecodeMemoryOperand16(DSize,pStart,iOpIndex,pIA32Decode);
else
iRet = DecodeMemoryOperand32(DSize,pStart,iOpIndex,pIA32Decode);
}
else
{
if(!IA32InstructionPrefixExists(0x67,pIA32Decode))
iRet = DecodeMemoryOperand16(DSize,pStart,iOpIndex,pIA32Decode);
else
iRet = DecodeMemoryOperand32(DSize,pStart,iOpIndex,pIA32Decode);
};
return iRet;
};
int GetOutputBuffer(int iOpIndex, char** strOutput,IA32InstructionDecode *pIA32Decode)
{
switch(iOpIndex)
{
case 1:
*strOutput = pIA32Decode->SIA32InstructionDescription.strOperandA;
return 1;
case 2:
*strOutput = pIA32Decode->SIA32InstructionDescription.strOperandB;
return 1;
case 3:
*strOutput = pIA32Decode->SIA32InstructionDescription.strOperandC;
return 1;
default:
return 0;
};
};
int strIsFPRegister(const char* str)
{
if(strlen(str) != 5)
return 0;
if(strstr(str,"st(") == str)
{
if(str[strlen(str)-1] != ')')
return 0;
if(!isdigit(str[strlen(str)-2]) || str[strlen(str)-2] > '7')
return 0;
return 1;
}
return 0;
};
int strIsBase10Int(const char* str)
{
char *p;
if(strlen(str))
{
strtoul(str,&p,10);
if(*p == 0)
return 1;
};
return 0;
};
int DecodeSingleOperand(const char * pLoadAddress, unsigned char *pStart, DefaultOperationSizeAttrib DSize, int iOpIndex, IA32InstructionDecode *pIA32Decode)
{
char strOperand[16];
char cAddressingMethod;
char *strOperandType;
char *strOutput;
unsigned char ModRM;
unsigned int uiOperandSize = 0;
unsigned int uiAddressSize;
unsigned char ucI8;
unsigned short usI16;
unsigned int uiI32;
unsigned int uiTemp;
char strSegOverride[10];
unsigned char ucSegOverride;
char strOpSize[20];
ucSegOverride = GetSegmentOverride(pIA32Decode);
GetSegmentOverrideStr(ucSegOverride,strSegOverride,sizeof(strSegOverride));
if(strlen(strSegOverride))
strcat(strSegOverride,":");
if(!GetOutputBuffer(iOpIndex,&strOutput,pIA32Decode))
return 0;
GetMemoryOperandSizeStr(strOutput,strOpSize,DSize,pIA32Decode);
if(strlen(strOpSize))
strcat(strOpSize," ");
strcpy(strOperand,strOutput);
if(!strlen(strOutput)||isupperstr(strOperand))
return 1;
if(strIsBase10Int(strOutput))
return 1;
/* terminate here if strOperand is an FP register */
if(strIsFPRegister(strOperand))
return 1;
cAddressingMethod = strOperand[0];
strOperandType = strOperand + 1;
if(strlen(strOperandType))
{
uiOperandSize = GetOperandTypeSize(strOperandType);
if(uiOperandSize & 0xFF000000)
{
/* we depend on the operand-size attribute */
if(DSize == OpSize32)
{
if(IA32InstructionPrefixExists(0x66,pIA32Decode))
/* use 16-bit operand-size */
uiOperandSize = uiOperandSize & 0x000000FF;
else
uiOperandSize = (uiOperandSize & 0x0000FF00) >> 8;
}
else
{ /* Default operand-size is 16-bit */
if(IA32InstructionPrefixExists(0x66,pIA32Decode))
/* use 16-bit operand-size */
uiOperandSize = (uiOperandSize & 0x0000FF00) >> 8;
else
uiOperandSize = uiOperandSize & 0x000000FF;
};
};
};
if(DSize == OpSize32)
{
if(IA32InstructionPrefixExists(0x67,pIA32Decode))
/* use 16-bit address-size */
uiAddressSize = 16;
else
uiAddressSize = 32;
}
else
{ /* Default address-size is 16-bit */
if(!IA32InstructionPrefixExists(0x67,pIA32Decode))
/* use 16-bit operand-size */
uiAddressSize = 16;
else
uiAddressSize = 32;
};
if(cAddressingMethod == 'e')
{
if(IsExplicitRegisterOperand(strOperand))
return DecodeExplicitGPRegister(DSize,iOpIndex,pIA32Decode);
else
return 0;
};
switch(cAddressingMethod)
{
case 'A':
case 'O':
/* Direct address - the instruction has no ModRM nor SIB bytes */
if(pIA32Decode->SIA32InstructionHelper.boolModRMExists)
return 0;
CopyMemory( &pIA32Decode->SIA32RawInstruction.URawDisplacement.cByteRawDisplacement,
pStart + pIA32Decode->SIA32InstructionHelper.cbRawPrefixes
+ pIA32Decode->SIA32InstructionHelper.cbRawOpcode,
uiAddressSize/8);
pIA32Decode->SIA32InstructionHelper.cbRawDisplacement = (unsigned char)(uiAddressSize/8);
if(uiOperandSize == 6)
{
/*
* In cases where we deal with 48-bit operand types, documentation is not clear
* about location of the extra two bytes representing the segment part, i.e. where
* do the two bytes fit in the IA32 general instruction format as outlined in
* "IA-32 Software Developer's manual volume 2A: instruction set reference",
* chapter 2, figure 2-1???
* So I just assume the two bytes immediately follow the 32-bit displacement, ooh!
* For representation of the disassembled code - this case will be treated as a
* special case
*/
CopyMemory( pIA32Decode->SIA32RawInstruction.URawImmediate.ca2ByteRawImmediate,
pStart + pIA32Decode->SIA32InstructionHelper.cbRawPrefixes
+ pIA32Decode->SIA32InstructionHelper.cbRawOpcode
+ pIA32Decode->SIA32InstructionHelper.boolModRMExists
+ pIA32Decode->SIA32InstructionHelper.boolSIBExists
+ pIA32Decode->SIA32InstructionHelper.cbRawDisplacement,
2);
pIA32Decode->SIA32InstructionHelper.cbRawImmediate += 2;
sprintf(strOutput,"0x%04X:[0x%08X]",
*(unsigned short*)pIA32Decode->SIA32RawInstruction.URawImmediate.ca2ByteRawImmediate,
*(unsigned int*)pIA32Decode->SIA32RawInstruction.URawDisplacement.ca2ByteRawDisplacement);
return 1;
};
if(!strlen(strSegOverride))
strcpy(strSegOverride,"ds:");
switch(uiAddressSize)
{
case 16:
sprintf(strOutput,"%s%s[0x%04X]",strOpSize,strSegOverride,
*((unsigned short*)pIA32Decode->SIA32RawInstruction.URawDisplacement.ca2ByteRawDisplacement));
break;
case 32:
sprintf(strOutput,"%s%s[0x%08X]",strOpSize,strSegOverride,
*((unsigned int*)pIA32Decode->SIA32RawInstruction.URawDisplacement.ca4ByteRawDisplacement));
break;
default:
return 0;
}
return 1;
case 'E':
case 'Q':
case 'W':
/* if the addressing method begins with one of above characters then it is R/M
* we need to determine the actual case. We certainly know that the instruction
* does have the ModRM byte
*/
if(!pIA32Decode->SIA32InstructionHelper.boolModRMExists)
{
ModRM = pStart[pIA32Decode->SIA32InstructionHelper.cbRawPrefixes + pIA32Decode->SIA32InstructionHelper.cbRawOpcode];
pIA32Decode->SIA32RawInstruction.ModRM = ModRM;
pIA32Decode->SIA32InstructionHelper.boolModRMExists = 1;
}
else
ModRM = pIA32Decode->SIA32RawInstruction.ModRM;
if((ModRM & 0xC0) == 0xC0)
/* we are dealing with a register operand here */
return DecodeSingleRegisterOperand(DSize,iOpIndex,pIA32Decode);
else
/* we are dealing with a memory operand */
return DecodeMemoryOperand(pStart,DSize,iOpIndex,pIA32Decode);
case 'C':
case 'D':
case 'G':
case 'P':
case 'R':
case 'S':
case 'T':
case 'V':
/* definitely registers here */
if(!pIA32Decode->SIA32InstructionHelper.boolModRMExists)
{
ModRM = pStart[pIA32Decode->SIA32InstructionHelper.cbRawPrefixes + pIA32Decode->SIA32InstructionHelper.cbRawOpcode];
pIA32Decode->SIA32RawInstruction.ModRM = ModRM;
pIA32Decode->SIA32InstructionHelper.boolModRMExists = 1;
};
return DecodeSingleRegisterOperand(DSize,iOpIndex,pIA32Decode);
case 'M':
return DecodeMemoryOperand(pStart,DSize,iOpIndex,pIA32Decode);
case 'I':
/* immediate */
CopyMemory(&pIA32Decode->SIA32RawInstruction.URawImmediate.cByteRawImmediate,
pStart +
pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists +
pIA32Decode->SIA32InstructionHelper.boolSIBExists +
pIA32Decode->SIA32InstructionHelper.cbRawDisplacement,
uiOperandSize);
pIA32Decode->SIA32InstructionHelper.cbRawImmediate += (unsigned char)uiOperandSize;
switch(uiOperandSize)
{
case 1:
ucI8 = pIA32Decode->SIA32RawInstruction.URawImmediate.cByteRawImmediate;
sprintf(strOutput,"0x%02X",ucI8);
return 1;
case 2:
usI16 = *((unsigned short*)pIA32Decode->SIA32RawInstruction.URawImmediate.ca2ByteRawImmediate);
sprintf(strOutput,"0x%04X",usI16);
return 1;
case 4:
uiI32 = *((unsigned int*)pIA32Decode->SIA32RawInstruction.URawImmediate.ca4ByteRawImmediate);
sprintf(strOutput,"0x%08X",uiI32);
return 1;
default:
return 0;
};
case 'J':
/* relative offset in immediate that needs to be added to the instruction pointer */
CopyMemory(&pIA32Decode->SIA32RawInstruction.URawImmediate.cByteRawImmediate,
pStart +
pIA32Decode->SIA32InstructionHelper.cbRawPrefixes +
pIA32Decode->SIA32InstructionHelper.cbRawOpcode +
pIA32Decode->SIA32InstructionHelper.boolModRMExists +
pIA32Decode->SIA32InstructionHelper.boolSIBExists +
pIA32Decode->SIA32InstructionHelper.cbRawDisplacement,
uiOperandSize);
pIA32Decode->SIA32InstructionHelper.cbRawImmediate += (unsigned char)uiOperandSize;
uiTemp = (unsigned int)(pLoadAddress + GetInstructionLength(pIA32Decode));
switch(uiOperandSize)
{
case 1:
ucI8 = pIA32Decode->SIA32RawInstruction.URawImmediate.cByteRawImmediate;
sprintf(strOutput,"0x%02X",(char)ucI8 + uiTemp);
return 1;
case 2:
usI16 = *((unsigned short*)pIA32Decode->SIA32RawInstruction.URawImmediate.ca2ByteRawImmediate);
sprintf(strOutput,"0x%04X",(short)usI16 + uiTemp);
return 1;
case 4:
uiI32 = *((unsigned int*)pIA32Decode->SIA32RawInstruction.URawImmediate.ca4ByteRawImmediate);
sprintf(strOutput,"0x%08X",(int)uiI32 + uiTemp);
return 1;
default:
return 0;
};
case 'X':
if(uiAddressSize == 16)
sprintf(strOutput,"%s[si]",strOpSize);
else
sprintf(strOutput,"%s[esi]",strOpSize);
return 1;
case 'Y':
if(uiAddressSize == 16)
sprintf(strOutput,"%s[di]",strOpSize);
else
sprintf(strOutput,"%s[edi]",strOpSize);
return 1;
default:
return 0;
}
};
int DecodeOperands(const char * pLoadAddress, unsigned char *pStart,DefaultOperationSizeAttrib DSize, IA32InstructionDecode *pIA32Decode)
{
if(strlen(pIA32Decode->SIA32InstructionDescription.strOperandA))
if(!DecodeSingleOperand(pLoadAddress,pStart,DSize,1,pIA32Decode))
return 0;
if(strlen(pIA32Decode->SIA32InstructionDescription.strOperandB))
if(!DecodeSingleOperand(pLoadAddress,pStart,DSize,2,pIA32Decode))
return 0;
if(strlen(pIA32Decode->SIA32InstructionDescription.strOperandC))
if(!DecodeSingleOperand(pLoadAddress,pStart,DSize,3,pIA32Decode))
return 0;
if(IsExplicitRegisterOperand(pIA32Decode->SIA32InstructionDescription.strOperandA))
strlwr(pIA32Decode->SIA32InstructionDescription.strOperandA);
if(IsExplicitRegisterOperand(pIA32Decode->SIA32InstructionDescription.strOperandB))
strlwr(pIA32Decode->SIA32InstructionDescription.strOperandB);
if(IsExplicitRegisterOperand(pIA32Decode->SIA32InstructionDescription.strOperandC))
strlwr(pIA32Decode->SIA32InstructionDescription.strOperandC);
return 1;
};
void PrintInstruction(const char*pLoadAddress, IA32InstructionDecode *pIA32Decode)
{
int i;
char strBuffer[80];
char strRemainder[80];
ZeroMemory(strBuffer,sizeof(strBuffer));
/* first print instruction address, and then raw bytes as they are in memory */
printf("\n %08X: ",pLoadAddress);
for(i = 0; i < pIA32Decode->SIA32InstructionHelper.cbRawPrefixes; i++)
sprintf(strBuffer + strlen(strBuffer),"%02X ",pIA32Decode->SIA32RawInstruction.caRawPrefixes[i]);
for(i = 0; i < pIA32Decode->SIA32InstructionHelper.cbRawOpcode; i++)
sprintf(strBuffer + strlen(strBuffer),"%02X ",pIA32Decode->SIA32RawInstruction.URawOpcode.ca2ByteRawOpcode[i]);
if(pIA32Decode->SIA32InstructionHelper.boolModRMExists)
sprintf(strBuffer + strlen(strBuffer),"%02X ",pIA32Decode->SIA32RawInstruction.ModRM);
if(pIA32Decode->SIA32InstructionHelper.boolSIBExists)
sprintf(strBuffer + strlen(strBuffer),"%02X ",pIA32Decode->SIA32RawInstruction.SIB);
for(i = 0; i < pIA32Decode->SIA32InstructionHelper.cbRawDisplacement; i++)
sprintf(strBuffer + strlen(strBuffer),"%02X ",pIA32Decode->SIA32RawInstruction.URawDisplacement.ca2ByteRawDisplacement[i]);
for(i = 0; i < pIA32Decode->SIA32InstructionHelper.cbRawImmediate; i++)
sprintf(strBuffer + strlen(strBuffer),"%02X ",pIA32Decode->SIA32RawInstruction.URawImmediate.ca2ByteRawImmediate[i]);
ZeroMemory(strRemainder,sizeof(strRemainder));
i = _snprintf(strRemainder,17,"%-17s",strBuffer);
printf("%s",strRemainder);
if(i < 0)
strcpy(strRemainder,strBuffer + strlen(strRemainder) + 1);
else
ZeroMemory(strRemainder,sizeof(strRemainder));
/* Now print the description, taking into account use of prefix */
if(strlen(pIA32Decode->SIA32InstructionDescription.strPrefix))
{
i = strlen(pIA32Decode->SIA32InstructionDescription.strPrefix - 1);
if(!isspace(pIA32Decode->SIA32InstructionDescription.strPrefix[i]))
strcat(pIA32Decode->SIA32InstructionDescription.strPrefix," ");
}
sprintf(strBuffer,"%s%s",pIA32Decode->SIA32InstructionDescription.strPrefix,
pIA32Decode->SIA32InstructionDescription.strOpcode);
printf(" %-12s",strBuffer);
/* There can never be operand A without operand B, nor operand B without C */
if(strlen(pIA32Decode->SIA32InstructionDescription.strOperandA))
{
printf("%s",pIA32Decode->SIA32InstructionDescription.strOperandA);
if(strlen(pIA32Decode->SIA32InstructionDescription.strOperandB))
{
printf(",%s",pIA32Decode->SIA32InstructionDescription.strOperandB);
if(strlen(pIA32Decode->SIA32InstructionDescription.strOperandC))
printf(",%s",pIA32Decode->SIA32InstructionDescription.strOperandC);
}
}
if(strlen(strRemainder))
printf("\n %-s",strRemainder);
};
void Disassemble(const char*pLoadAddress,DefaultOperationSizeAttrib DSize,unsigned char *pStart, unsigned char *pEnd)
{
IA32InstructionDecode IA32Decode;
int iRet = 1;
while(pStart < pEnd)
{
#ifdef _DEBUG
if(pLoadAddress == (char*)0x0438cca)
Sleep(0);
#endif
ZeroMemory(&IA32Decode,sizeof(IA32Decode));
iRet = FetchOpcode(pLoadAddress,pStart,&IA32Decode,DSize);
if(iRet == 0)
return;
iRet = DecodeOperands(pLoadAddress,pStart,DSize,&IA32Decode);
if((iRet == 0)||!strcmpi(IA32Decode.SIA32InstructionDescription.strOpcode,"???"))
{
/* the first byte can be either a prefix or the opcode, let's deal with
* each case individually - cheating where necessary
*/
if(IA32Decode.SIA32InstructionHelper.cbRawPrefixes)
{
IA32Decode.SIA32RawInstruction.URawOpcode.cByteRawOpcode =
IA32Decode.SIA32RawInstruction.caRawPrefixes[0];
}
ZeroMemory(&IA32Decode.SIA32RawInstruction.URawOpcode.cByteRawOpcode + 1,
sizeof(IA32Decode) - (
sizeof(IA32Decode.SIA32RawInstruction.caRawPrefixes)
+ sizeof(IA32Decode.SIA32RawInstruction.URawOpcode.cByteRawOpcode)));
IA32Decode.SIA32InstructionDescription.strOpcode[0] = 0;
IA32Decode.SIA32InstructionHelper.cbRawOpcode = 1;
};
if(iRet)
iRet = GetInstructionLength(&IA32Decode);
else
iRet = 1;
PrintInstruction(pLoadAddress,&IA32Decode);
pStart += iRet;
pLoadAddress += iRet;
}
};
Simply copy the SOURCES DriverMain.C and the MAKEFILE in the same folder. Open the WDK command promt and type: Build.
An example dump with the program posted above looks like this. This is a disassembled piece of code from the game CombatArms. I've verefied it and this is indeed the code at that exact offset.