2023年12月6日发(作者:)

实现Windbgx64汇编功能

实现windbg x64汇编功能

背景

  熟悉windbg的都知道,a指令,只支持x86,另外经我研究,虽然引擎中扩展了I386|ARM|IA64|AMD64|EBC的指令集,但是后几种只有

反汇编能力,而并没有汇编能力。因此这是个突破点,然而汇编器源码这种东西是比较稀缺的,无奈之下为了实现amd64汇编我选择了

工具,利用该用具生成机器码

0:000> !a -s AMD64

usage: !a [-s ProcessorType] [-a Address]

Optional ProcessorType:I386|ARM|IA64|AMD64|EBC

Default ProcessorType is I386;Default Address is current $ip

example:!a -s AMD64 -a .

Assemble on AMD64 at 00007FFD75B81970

please input asm code, [enter] to leave

mov r8,0

mov r8,0

00007ffd`75b81970 49c7c000000000 mov r8,0

mov r8,gs:[0]

mov r8,gs:[0]

00007ffd`75b81977 654c8b mov r8,qword ptr gs:[0] gs:00000000`00000000=

asm edit leave

开发Windbg插件

//

#include "DbgEng.h"

#include

#include

#include

#pragma comment(lib,"")

#define EXT_MAJOR_VER 1

#define EXT_MINOR_VER 0

extern "C" HRESULT CALLBACK

DebugExtensionInitialize(PULONG Version, PULONG Flags)

{

*Version = DEBUG_EXTENSION_VERSION(EXT_MAJOR_VER, EXT_MINOR_VER);

*Flags = 0; // Reserved for future use.

return S_OK;

}

extern "C" void CALLBACK

DebugExtensionNotify(ULONG Notify, ULONG64 Argument)

{

UNREFERENCED_PARAMETER(Argument);

switch (Notify) {

// A debugging session is active. The session may not necessarily be suspended.

case DEBUG_NOTIFY_SESSION_ACTIVE:

break;

// No debugging session is active.

case DEBUG_NOTIFY_SESSION_INACTIVE:

break;

// The debugging session has suspended and is now accessible.

case DEBUG_NOTIFY_SESSION_ACCESSIBLE:

break;

// The debugging session has started running and is now inaccessible.

case DEBUG_NOTIFY_SESSION_INACCESSIBLE:

break; break; } return;}extern "C" void CALLBACKDebugExtensionUninitialize(void)

{ return;}HRESULT CALLBACKhelloworld(PDEBUG_CLIENT pDebugClient, PCSTR args)

{ UNREFERENCED_PARAMETER(args); IDebugControl* pDebugControl; if (SUCCEEDED(pDebugClient->QueryInterface(__uuidof(IDebugControl), (void **)&pDebugControl))) { pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "Hello World!n"); pDebugControl->Release(); } return S_OK;}//返回参数长度,和起始位置int GetParamVal(PCSTR& begin, PCSTR& end){ PCSTR truebegin = 0, trueend = 0; while (*begin) { if (*begin != ' ' && *begin != 't') { truebegin = begin; break; } begin++; } trueend = truebegin; do { if (*trueend == '-' || *trueend == '0') { break; } trueend++; } while (true); return trueend - truebegin;}PSTR getnextnonblank(PSTR begin){ while (*begin) { if (*begin != ' ' && *begin != 't') break; begin++; } return begin;}PSTR getnextchar(PSTR begin, char ch){ while (*begin) { if (*begin == ch) break; begin++; } return begin;}

bool ResolveSymbolInExpression(IDebugControl* pDebugControl, PSTR asmcode, PSTR outcode, ULONG64 Xip)

{

/*

//找到操作码起始位置

PSTR opcode, opdata;

int opcodelen, opdatalen;

asmcode = getnextnonblank(asmcode);

if (!*asmcode)//找不到操作码

return false;

char si[] = " ,,,,,";

int index = 0;

char exp[256];

__debugbreak();

DEBUG_VALUE value;

do

{

opcode = asmcode;

asmcode = getnextchar(asmcode, si[index]);

opcodelen = asmcode - opcode;

strncpy(exp, opcode, opcodelen);

exp[opcodelen] = '0';

memset(&value, 0, sizeof(value));

if (SUCCEEDED(pDebugControl->Evaluate(exp, DEBUG_VALUE_INT64, &value, NULL)))

{

//若能解析

sprintf(exp, "%I64d", (LONG64)value.I64);

opcodelen = strlen(exp);

strncpy(outcode, exp, opcodelen);

outcode[opcodelen] = '0';

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "解析exp=%sn", outcode);

}

else

{

//不能解析

strncpy(outcode, opcode, opcodelen);

outcode[opcodelen] = '0';

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "无法解析exp=%sn", exp);

}

outcode += opcodelen;

asmcode = getnextnonblank(asmcode + 1);

*outcode = si[index];

outcode++;

index++;

} while (*asmcode);

outcode[-1] = '0';

*/

strcpy(outcode, asmcode);

return true;

}

bool GetByteCode(IDebugControl* pDebugControl, PSTR asmcode, PSTR outbyte, PULONG byteswrite)

{

__debugbreak();

char buf[256], asmpath[256], objpath[256], ml64path[256], msvcr100[256];

bool ret = false;

GetCurrentDirectoryA(256, buf);

sprintf(asmpath, "%", buf);

sprintf(objpath, "%", buf);

sprintf(ml64path, "%", buf);

sprintf(msvcr100, "%", buf);

FILE* fpasm = NULL,*fpobj = NULL;

fpasm = fopen(asmpath, "w");

if (!fpasm)

{

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "无法创建asmn");

}

else if (!PathFileExistsA(ml64path))

{

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "不存在n");

}

else if (!PathFileExistsA(msvcr100))

{

{

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "不存在n");

}

else

{

fputs(".CODEn", fpasm);

fputs("Entry PROCn", fpasm);

fputs(asmcode, fpasm);

fputs("nEntry ENDPn", fpasm);

fputs("ENDn", fpasm);

fclose(fpasm);

fpasm = NULL;

if (!PathFileExistsA(objpath) || DeleteFileA(objpath))

{

WinExec("ml64 ", SW_HIDE);

Sleep(200);

fpobj = fopen(objpath, "rb");

if (!fpobj)

{

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "语法错误n");

}

else

{

char* data = new char[256];

fread(data, 256, 1, fpobj);

int offset = 0x18;

unsigned short datasize;

offset += *(unsigned short*)(data + offset);

datasize = *(unsigned short*)(data + 0x24);

//此时data+offset处的datasize个字节即为汇编生成的机器码

//写入内存

memcpy(outbyte, data + offset, datasize);

*byteswrite = datasize;

delete[]data;

ret = true;

}

}

else

{

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "obj文件无法删除n");

}

}

if (fpasm)

fclose(fpasm);

if (fpobj)

fclose(fpobj);

//DeleteFileA(asmpath);

DeleteFileA(objpath);

return ret;

}

HRESULT CALLBACK

a(PDEBUG_CLIENT pDebugClient, PCSTR args)

{

UNREFERENCED_PARAMETER(args);

IDebugControl* pDebugControl;

if (SUCCEEDED(pDebugClient->QueryInterface(__uuidof(IDebugControl),(void **)&pDebugControl)))

{

HRESULT result = 0;

ULONG OriProcessorType = 0, CurProcessorType = 0;

if (!SUCCEEDED(pDebugControl->GetEffectiveProcessorType(&OriProcessorType)))

OriProcessorType = IMAGE_FILE_MACHINE_I386;

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "usage: !a [-s ProcessorType] [-a Address]n");

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "tOptional ProcessorType:I386|ARM|IA64|AMD64|EBCn");

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "tDefault ProcessorType is I386;Default Address is current $ipn");

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "example:!a -s AMD64 -a .n");

PSTR pt = (PSTR)args;

DEBUG_VALUE value;

ULONG64 Address;

char exp[256] = "$ip",ProcessorName[256];

char exp[256] = "$ip",ProcessorName[256];

PCSTR b = pt, e = pt;

CurProcessorType = IMAGE_FILE_MACHINE_I386;

strcpy(ProcessorName, "I386");

if (b = strstr(pt, "-s"))

{

if (strstr(pt, "I386"))

{

CurProcessorType = IMAGE_FILE_MACHINE_I386;

strcpy(ProcessorName, "I386");

}

else if (strstr(pt, "ARM"))

{

CurProcessorType = IMAGE_FILE_MACHINE_ARM;

strcpy(ProcessorName, "ARM");

}

else if (strstr(pt, "IA64"))

{

CurProcessorType = IMAGE_FILE_MACHINE_IA64;

strcpy(ProcessorName, "IA64");

}

else if (strstr(pt, "AMD64"))

{

CurProcessorType = IMAGE_FILE_MACHINE_AMD64;

strcpy(ProcessorName, "AMD64");

}

else if (strstr(pt, "EBC"))

{

CurProcessorType = IMAGE_FILE_MACHINE_EBC;

strcpy(ProcessorName, "EBC");

}

}

else if (b = strstr(pt, "-a"))

{

e = b;

int len = GetParamVal(b, e);

if (len)

{

strncpy(exp, b, len);

exp[len] = '0';

}

}

pDebugControl->Evaluate(exp, (OriProcessorType == IMAGE_FILE_MACHINE_I386) ? DEBUG_VALUE_INT32 : DEBUG_VALUE_INT64, &value, NULL);

Address = (OriProcessorType == IMAGE_FILE_MACHINE_I386) ? value.I32 : value.I64;

pDebugControl->SetEffectiveProcessorType(CurProcessorType);

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "Assemble on %s at %Nn please input asm code, [enter] to leaven", ProcessorName, Address);

char Inputbuf[256];

while (true)

{

ULONG64 NextAddr = Address,NextAddr2;

memset(Inputbuf, 0, 256);

pDebugControl->Input(Inputbuf, 256, NULL);

if (strlen(Inputbuf) == 0)

break;

switch (CurProcessorType)

{

case IMAGE_FILE_MACHINE_I386:

strcpy(pt, Inputbuf);

//逐行反汇编

result = pDebugControl->Assemble(Address, Inputbuf, &NextAddr);

//打印结果

if (SUCCEEDED(result))

{

DEBUG_DISASM_SOURCE_LINE_NUMBER | DEBUG_DISASM_SOURCE_FILE_NAME, &NextAddr2);

Address = NextAddr;

}

break;

case IMAGE_FILE_MACHINE_AMD64:

{

char bytecode[256],fixasmcode[256];

bool suc = true;

pDebugControl->OutputDisassembly(DEBUG_OUTCTL_ALL_CLIENTS, Address, DEBUG_DISASM_EFFECTIVE_ADDRESS | DEBUG_DISASM_MATCHING_S

bool suc = true;

//使用ml64进行解析:

//1.先将Inputbuf中的符号解析为数据

suc = ResolveSymbolInExpression(pDebugControl, Inputbuf, fixasmcode, Address);

if(!suc)

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "unresolve symboln");

//2.使用ml64解析并取得obj机器码

else

{

ULONG bytewrite = 0;

suc = GetByteCode(pDebugControl, fixasmcode, bytecode, &bytewrite);

if(!suc || !bytewrite)

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "file op or disasm failn");

else

{

//3.写入虚拟内存

IDebugDataSpaces* dataspace;

if (SUCCEEDED(pDebugClient->QueryInterface(__uuidof(IDebugDataSpaces), (void **)&dataspace)))

{

if (!SUCCEEDED(dataspace->WriteVirtual(Address, (PVOID)bytecode, bytewrite, NULL)))

{

suc = false;

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "can't write to memoryn");

}

}

else

{

suc = false;

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "can't obtain IDebugDataSpacesn");

}

if (suc)

{

pDebugControl->OutputDisassembly(DEBUG_OUTCTL_ALL_CLIENTS, Address, DEBUG_DISASM_EFFECTIVE_ADDRESS | DEBUG_DISASM_MATCH

DEBUG_DISASM_SOURCE_LINE_NUMBER | DEBUG_DISASM_SOURCE_FILE_NAME, &NextAddr2);

Address = NextAddr2;

}

}

}

}

break;

default:

break;

}

}

pDebugControl->Output(DEBUG_OUTPUT_NORMAL, "asm edit leaven", ProcessorName, Address);

pDebugControl->SetEffectiveProcessorType(OriProcessorType);

pDebugControl->Release();

}

return S_OK;

}

EXPORTS

DebugExtensionNotify

DebugExtensionInitialize

DebugExtensionUninitialize

a