为OllyDbg增加LastBranchRecord功能 关于CPU的分枝监视功能,已经有牛人写过文章,<软件调试>书中也有详细介绍,就不多说了。直接给代码。
另外,我的代码是写在自己的插件中的,一堆乱七八糟的东西,就不给bin了,代码还算简单。
测试机器为WinXP Sp2,CPU为P4 Family0F Model6。 在驱动中创建与Ring3的共享内存,这里的代码直接从sudami的文章中copy的哈。 // 创建共享内存向Ring3传递数据
g_SharedMem = ExAllocatePool(NonPagedPool, PAGE_SIZE);
if (!g_SharedMem)
goto __Fail;
g_MdlShared = IoAllocateMdl(g_SharedMem,
PAGE_SIZE,
FALSE,
FALSE,
NULL);
if (!g_MdlShared)
{
ExFreePool(g_SharedMem);
goto __Fail;
}
MmBuildMdlForNonPagedPool(g_MdlShared); 将内存映射到OllyDbg用户空间:
case IRP_MJ_DEVICE_CONTROL:
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_INSTALL_HOOK:
...
if (OutputLen >= sizeof(PVOID))
{
MapAddress = MmMapLockedPagesSpecifyCache (
g_MdlShared,
UserMode,
MmNonCached,
NULL,
FALSE,
NormalPagePriority );
if (MapAddress)
{
//DbgPrint("Map ShareMem ok, MapAddress = %08X", MapAddress);
*(PVOID *)OutputBuffer = MapAddress;
InfoSize = sizeof(PVOID);
}
}
... 挂INT1:
volatile __declspec(naked) void NewInt01()
{
// - Interrupt 1 Handler -
//
// offset | contains
// ---------+-----------------------------
// esp : EIP Context
// esp + 4 : CS Context
// esp + 8 : EFLAGS Context
__asm
{
pushad
push fs
push ds
push es
mov eax, 30h
mov fs, ax
mov eax, 23h
mov ds, ax
mov es, ax
call dword ptr [IoGetCurrentProcess]
cmp eax, g_ObjProc // Debuggee?
jne __oldint01
mov eax, dr6
bt eax, 0Eh //单步?
jnc __oldint01
mov eax, g_FastTrace //配置选项
cmp eax, 1
jne __oldint01
mov edi, g_SharedMem
mov ecx, MSR_LASTBRANCH_TOS
rdmsr
mov ebx, eax
and ebx, 0Fh //TOS = 4位
mov ecx, MSR_LASTBRANCH_0_FROM_LIP
add ecx, ebx
rdmsr
mov [edi], eax
mov ecx, MSR_LASTBRANCH_0_TO_LIP
add ecx, ebx
rdmsr
mov [edi+4], eax
mov ecx, MSR_DEBUGCTLA
rdmsr
or eax, 3 // BTF & LBR
wrmsr
__oldint01:
pop es
pop ds
pop fs
popad
jmp g_KiTrap01;
}
}
这里没有用DebugStore,直接从LBR栈取数据,省事,而且支持多处理器。 下面是Ring3部分的代码。Hook了OllyDbg的WaitForDebugEvent。
case EXCEPTION_SINGLE_STEP: //单步异常
// 判断一下是否处于TraceInto或TraceOver,这个没写,再说
// 有时第1条数据记录的是内核地址,这里可以判断一下
if (g_Ring0Options.FastTrace)
{
if (g_dwLBRCount < MAX_LBR_NUMBER)
{
g_LBRRecord[g_dwLBRCount].dwIndex = g_dwLBRCount;
g_LBRRecord[g_dwLBRCount].dwThreadId = lpDbgEvent->dwThreadId;
g_LBRRecord[g_dwLBRCount].dwFrom = ((PDWORD)g_SharedMem)[0];
g_LBRRecord[g_dwLBRCount].dwTo = ((PDWORD)g_SharedMem)[1];
// 在这里读取代码,以防备SMC破坏代码
if (_Readcommand(((PDWORD)g_SharedMem)[0], g_LBRRecord[g_dwLBRCount].CmdFrom) &&
_Readcommand(((PDWORD)g_SharedMem)[1], g_LBRRecord[g_dwLBRCount].CmdTo))
{
_Addsorteddata(&g_LBRTable.data, &g_LBRRecord[g_dwLBRCount++]);
}
else
{
_Addtolist(0, 1, "LBR Buffer Overrun");
}
}
}
... 剩下的就是OD插件界面相关的,从Conditional Branch Logger抄的。
需要说明的是,OD自己的Trace功能,若选择Always trace over system DLLs,估计是用int3断点来获取调用后的控制。
用BTF位,则任何控制转移都会被记录,不过可以在WaitForDebugEvent中筛选一下记录的数据。另外,也可以在驱动中做
得更好点,只在运行被调试进程时才打开LBR。不过我的测试似乎性能下降不大,至少不比OD自己的跟踪差。 上个图。加载一个用UPX加壳的程序,用OllyBone对第1区段下执行断点。OllyBone我也抄了,不过功能有点
问题,这里先不管它了,对这个程序是可以的。
Ctrl-F11开始跟。到OEP停下显示数据。共90000多条数据。可以清楚看到是怎样跳到OEP的,对于有花指令的代码有点用。
当然,最好不要加载完就这样干,那样数据太多了。
本来想把OD的语法配色也搞出来,感觉比较复杂,就算啦。图标也用的CBL插件的。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: