1.加载调试符号链接文件并放入d:/symbols
目录下.
0:000> .sympath srv*d:\symbols*http://msdl.microsoft.com/download/symbols
Symbol search path is: srv*d:\symbols*http://msdl.microsoft.com/download/symbols
Expanded Symbol search path is: srv*d:\symbols*http://msdl.microsoft.com/download/symbols
0:000> .reload
Reloading current modules
2.位于fs:[0x30]
的位置就是PEB结构的指针,接着我们分析如何得到的该指针,并通过通配符找到TEB结构的名称.
0:000> dt ntdll!*teb*
ntdll!_TEB
ntdll!_GDI_TEB_BATCH
ntdll!_TEB_ACTIVE_FRAME
ntdll!_TEB_ACTIVE_FRAME_CONTEXT
ntdll!_TEB_ACTIVE_FRAME_CONTEXT
3.接着可通过dt命令,查询下ntdll!_TEB
结构,如下可看到0x30
处ProcessEnvironmentBlock
存放的正是PEB结构.
0:000> dt -rv ntdll!_TEB
struct _TEB, 66 elements, 0xfb8 bytes
+0x000 NtTib : struct _NT_TIB, 8 elements, 0x1c bytes # NT_TIB结构
+0x018 Self : Ptr32 to struct _NT_TIB, 8 elements, 0x1c bytes # NT_TIB结构
+0x020 ClientId : struct _CLIENT_ID, 2 elements, 0x8 bytes # 保存进程与线程ID
+0x02c ThreadLocalStoragePointer : Ptr32 to Void
+0x030 ProcessEnvironmentBlock : Ptr32 to struct _PEB, 65 elements, 0x210 bytes # PEB结构
偏移地址0x18
是_NT_TIB
结构,也就是指向自身偏移0x0
的位置.
0:000> r $teb
$teb=7ffdf000
0:000> dd $teb+0x18
7ffdf018 7ffdf000 00000000 00001320 00000c10
7ffdf028 00000000 00000000 7ffd9000 00000000
而!teb
地址加0x30
正是PEB
的位置,可以使用如下命令验证.
0:000> dd $teb+0x30
7ffdf030 7ffd9000 00000000 00000000 00000000
7ffdf040 00000000 00000000 00000000 00000000
0:000> !teb
TEB at 7ffdf000
ExceptionList: 0012fd0c
StackBase: 00130000
StackLimit: 0012e000
SubSystemTib: 00000000
FiberData: 00001e00
ArbitraryUserPointer: 00000000
Self: 7ffdf000
EnvironmentPointer: 00000000
ClientId: 00001320 . 00000c10
RpcHandle: 00000000
Tls Storage: 00000000
PEB Address: 7ffd9000 # 此处teb地址
上方的查询结果可得知偏移位置fs:[0x18]
正是TEB的基址TEB:7ffdf000
0:000> dd fs:[0x18]
003b:00000018 7ffdf000 00000000 000010f4 00000f6c
003b:00000028 00000000 00000000 7ffda000 00000000
0:000> dt _teb 0x7ffdf000
ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : (null)
+0x020 ClientId : _CLIENT_ID # 这里保存进程与线程信息
0:000> dt _CLIENT_ID 0x7ffdf000 # 查看进程详细结构
ntdll!_CLIENT_ID
+0x000 UniqueProcess : 0x0012fd0c Void # 获取进程PID
+0x004 UniqueThread : 0x00130000 Void # 获取线程PID
上方TEB首地址我们知道是fs:[0x18]
,接着我们通过以下公式计算得出本进程的进程ID.
在Windows系统中如果想要获取到PID进程号,可以使用NtCurrentTeb()
这个系统API来实现,但这里我们手动实现该API的获取过程.
获取进程PID:
#include "stdafx.h"
#include <Windows.h>
DWORD GetPid(){
DWORD dwPid=0;
__asm
{
mov eax,fs:[0x18] // 获取PEB地址
add eax,0x20 // 加0x20得到进程PID
mov eax,[eax]
mov dwPid,eax
}
return dwPid;
}
int main()
{
printf("%d\n",GetPid());
return 0;
}
获取线程PID:
#include "stdafx.h"
#include <Windows.h>
DWORD GetPid(){
DWORD dwPid=0;
__asm
{
mov eax,fs:[0x18] // 获取PEB地址
add eax,0x20 // 加0x20得到进程PID
add eax,0x04 // 加0x04得到线程PID
mov eax,[eax]
mov dwPid,eax
}
return dwPid;
}
int main()
{
printf("%d\n",GetPid());
return 0;
}
通过标志反调试: 下方的调试标志BeingDebugged
是Char类型,为1表示调试状态.为0表示没有调试.可以用于反调试.
0:000> dt _peb
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
#include "stdafx.h"
#include <Windows.h>
int main()
{
DWORD dwIsDebug = 0;
__asm
{
mov eax, fs:[0x18]; // 获取TEB
mov eax, [eax + 0x30]; // 获取PEB
movzx eax, [eax + 2]; // 获取调试标志
mov dwIsDebug,eax
}
if (1 == dwIsDebug)
{
printf("正在被调试");
}
else
{
printf("没有被调试");
}
return 0;
}
通过API反调试:
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
int main()
{
STARTUPINFO temp;
temp.cb = sizeof(temp);
GetStartupInfo(&temp);
if (temp.dwFlags != 1)
{
ExitProcess(0);
}
printf("程序没有被反调试");
return 0;
}