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