Windebug 专题

 

  1. windbg-易用cmdtree入门

简介

 

         cmdtree是windbg未文档化的一个UI窗口,用于简化我们使用windbg,结合windbgscript和DML存成一个文件夹,简单但非常实用

效果图

https://i-blog.csdnimg.cn/blog_migrate/f90b43c777267efc738cc5545b5683b0.jpeg

整体格式整体格式如下:

https://i-blog.csdnimg.cn/blog_migrate/52d0baabf542e128b80b28c77b44eb87.jpeg

 

 

基本语法

 

Magic term

 

         windbg ANSICommand Tree 1.0

 

windbg ANSICommand Tree 1.1

 

可以通过搜索windbg自身内容找到:

https://i-blog.csdnimg.cn/blog_migrate/d3bcc4c913d1e619c536fc5b345d9a12.jpeg

 

 

 

注意点:

 

1.      1.0和1.1区别在于显示排序,1.1使用的是倒序(1.1会把最后的命令显示在最上面)

 

2.      字符固定的,不能改大小写,如windbg ANSI Command tree 1.0都会导致cmdtree加载失败

 

3.      前面不能有空格或空行,必须顶格

 

 

title

 

         做为UI窗口标题显示,如果同时使用了多个cmdtree文件,它方便区分不同的文件

 

格式:

 

title  {“”}

 

 

title

 

{“”}

 

 

 

注意点:

 

1.      大小写敏感

 

2.      前面不能有空格,必须顶格

 

3.      title和左括号中间必须有一个空格或tab键或回车键

 

4.      括号中内容不能使用中文

 

 

 

body

 

用来区分header和content

 

规则类似于title

 

 

 

content(正文)

 

1.      整个结构就是一个简单的树形结构

 

2.      {“描述”} {“命令”}为元素基本形式,两括号之间有无空格都OK

 

3.      双击{“描述”}行后,会执行{“描述”}后对应的{“命令”}

 

4.      分层是使用空格或tab来实现的,下一层总是要比上一次多一个空格或tab

 

 

 

建议都换行,使用tab,看起来整齐

 

2.windbg-PE完整分析

1.PE结构常用的结构体

 

0:001> dt ntdll!*IMAGE*

          ntdll!_IMAGE_NT_HEADERS

          ntdll!_IMAGE_FILE_HEADER

          ntdll!_IMAGE_OPTIONAL_HEADER

          ntdll!_IMAGE_DOS_HEADER

          ntdll!_IMAGE_DATA_DIRECTORY

仅在exe使用了winnt.h(驱动ntimage.h)才会显示其他结构体,如IID:

0:001> dt ole32!_IMAGE_IMPORT_DESCRIPTOR

   +0x000 Characteristics  : Uint4B

   +0x000 OriginalFirstThunk : Uint4B

   +0x004 TimeDateStamp    : Uint4B

   +0x008 ForwarderChain   : Uint4B

   +0x00c Name             : Uint4B

   +0x010 FirstThunk       : Uint4B

 

2.DOS头

 

0:001> lmvm kernel32

start    end        module name

76d00000 76e10000   kernel32   (pdb symbols)          c:\mysymbol\wkernel32.pdb\69083C6D23244DC3BF8B73A9EE01C7742\wkernel32.pdb

    Loaded symbol image file: C:\Windows\syswow64\kernel32.dll

    Image path: C:\Windows\syswow64\kernel32.dll

0:001> dt ntdll!_IMAGE_DOS_HEADER 76d00000

   +0x000 e_magic          : 0x5a4d

   +0x002 e_cblp           : 0x90

   +0x004 e_cp             : 3

   +0x006 e_crlc           : 0

   +0x008 e_cparhdr        : 4

   +0x00a e_minalloc       : 0

   +0x00c e_maxalloc       : 0xffff

   +0x00e e_ss             : 0

   +0x010 e_sp             : 0xb8

   +0x012 e_csum           : 0

   +0x014 e_ip             : 0

   +0x016 e_cs             : 0

   +0x018 e_lfarlc         : 0x40

   +0x01a e_ovno           : 0

   +0x01c e_res            : [4] 0

   +0x024 e_oemid          : 0

   +0x026 e_oeminfo        : 0

   +0x028 e_res2           : [10] 0

   +0x03c e_lfanew         : 232   // 指向PE头

 

3.PE头

 

0:001> dt ntdll!_IMAGE_NT_HEADERS 76d00000+0n232

   +0x000 Signature        : 0x4550

   +0x004 FileHeader       : _IMAGE_FILE_HEADER

   +0x018 OptionalHeader   : _IMAGE_OPTIONAL_HEADER

0:001> ? 76d00000+0n232

Evaluate expression: 1993343208 = 76d000e8    // PE头地址

 

4.可选头中找到EXPORT表基地址

 

0:001> dt ntdll!_IMAGE_OPTIONAL_HEADER -v -ny DataDirectory 76d000e8+0x018

struct _IMAGE_OPTIONAL_HEADER, 31 elements, 0xe0 bytes

   +0x060 DataDirectory : [16] struct _IMAGE_DATA_DIRECTORY, 2 elements, 0x8 bytes

DataDirectory[0]即为导出表,地址为76d00160

0:001> ? 76d000e8+0x018+0x060

Evaluate expression: 1993343328 = 76d00160

 

5.找到EXPORT实际地址

 

0:001> dt ole32!_IMAGE_DATA_DIRECTORY 76d00160

   +0x000 VirtualAddress   : 0xc0070

   +0x004 Size             : 0xa9b1

0:001> ? 76d00000+0xc0070   //kernel32基地址+VA

Evaluate expression: 1994129520 = 76dc0070

0:001> dt ole32!IMAGE_EXPORT_DIRECTORY  76dc0070

   +0x000 Characteristics  : 0

   +0x004 TimeDateStamp    : 0x5609edc5

   +0x008 MajorVersion     : 0

   +0x00a MinorVersion     : 0

   +0x00c Name             : 0xc35e0  // 模块的真实名称

   +0x010 Base             : 1        // 基数,加上序数就是函数地址数组的索引

   +0x014 NumberOfFunctions : 0x554   // 指向的数组元素个数

   +0x018 NumberOfNames    : 0x554    // 指向的数组元素个数

   +0x01c AddressOfFunctions : 0xc0098// 指向函数地址数组

   +0x020 AddressOfNames   : 0xc15e8  // 指向函数名字数组

   +0x024 AddressOfNameOrdinals : 0xc2b38// 指向输出序号数组

 

6.遍历EXPORT

 

模块名:

0:001> da 76d00000+0xc35e0

76dc35e0  "KERNEL32.dll"

 

原理:AddressOfNames和AddressOfNameOrdinals一样多,一个名字肯定只有一个地址(function),但一个地址可能有多个名字(name)

 

先用loadpe看下kernel32:

https://i-blog.csdnimg.cn/blog_migrate/9d5d70cdd29fb0683b480c6b8fc49334.jpeg

 

函数遍历

0:001> .foreach(place {dd 76dc0098 L10}){ln ${place}+76d00000}

(76d13368)   kernel32!BaseThreadInitThunk   |  (76d13386)   kernel32!ConDllInitialize

Exact matches:

    kernel32!BaseThreadInitThunk = <no type information>

(76dc0070)   kernel32!$$VProc_ImageExportDirectory+0xa434   |  (76de0000)   kernel32!BasepAllowResourceConversion

(76dc0070)   kernel32!$$VProc_ImageExportDirectory+0x9eb5   |  (76de0000)   kernel32!BasepAllowResourceConversion

(76dc0070)   kernel32!$$VProc_ImageExportDirectory+0x9ed6   |  (76de0000)   kernel32!BasepAllowResourceConversion

(76d15448)   kernel32!ActivateActCtx   |  (76d15479)   kernel32!ReleaseActCtx

Exact matches:

    kernel32!ActivateActCtx = <no type information>

(76d2ed3e)   kernel32!AddAtomA   |  (76d2edb4)   kernel32!FindAtomA

Exact matches:

    kernel32!AddAtomA = <no type information>

(76d2cdd4)   kernel32!AddAtomW   |  (76d2cdee)   kernel32!DeleteAtom

Exact matches:

    kernel32!AddAtomW = <no type information>

(76db6b86)   kernel32!AddConsoleAliasA   |  (76db6be3)   kernel32!GetConsoleAliasW

Exact matches:

    kernel32!AddConsoleAliasA = <no type information>

(76db6b1c)   kernel32!AddConsoleAliasW   |  (76db6b86)   kernel32!AddConsoleAliasA

Exact matches:

    kernel32!AddConsoleAliasW = <no type information>

(76dc0070)   kernel32!$$VProc_ImageExportDirectory+0x9ef4   |  (76de0000)   kernel32!BasepAllowResourceConversion

(76d94f72)   kernel32!AddIntegrityLabelToBoundaryDescriptor   |  (76d94f9d)   kernel32!CreatePrivateNamespaceA

Exact matches:

    kernel32!AddIntegrityLabelToBoundaryDescriptor = <no type information>

(76d87538)   kernel32!AddLocalAlternateComputerNameA   |  (76d87581)   kernel32!RemoveLocalAlternateComputerNameW

Exact matches:

    kernel32!AddLocalAlternateComputerNameA = <no type information>

(76d8744d)   kernel32!AddLocalAlternateComputerNameW   |  (76d87538)   kernel32!AddLocalAlternateComputerNameA

Exact matches:

    kernel32!AddLocalAlternateComputerNameW = <no type information>

(76d2d510)   kernel32!AddRefActCtx   |  (76d2d521)   kernel32!GetCurrentActCtx

Exact matches:

    kernel32!AddRefActCtx = <no type information>

(76d3915f)   kernel32!AddSIDToBoundaryDescriptor   |  (76d39257)   kernel32!LocalOpenPerformanceData

Exact matches:

    kernel32!AddSIDToBoundaryDescriptor = <no type information>

(76d8f4c2)   kernel32!AddSecureMemoryCacheCallback   |  (76d8f4ea)   kernel32!RemoveSecureMemoryCacheCallback

Exact matches:

    kernel32!AddSecureMemoryCacheCallback = <no type information>

 

函数名遍历

0:001> .foreach(place {dd 76dc15e8}){r @$t0=${place}+76d00000; .if(@$t0<86d00000){da @$t0}}

76dc35ed  "AcquireSRWLockExclusive"

76dc3605  "AcquireSRWLockShared"

76dc361a  "ActivateActCtx"

76dc3629  "AddAtomA"

76dc3632  "AddAtomW"

76dc363b  "AddConsoleAliasA"

76dc364c  "AddConsoleAliasW"

76dc365d  "AddDllDirectory"

76dc366d  "AddIntegrityLabelToBoundaryDescr"

76dc368d  "iptor"

76dc3693  "AddLocalAlternateComputerNameA"

76dc36b2  "AddLocalAlternateComputerNameW"

76dc36d1  "AddRefActCtx"

76dc36de  "AddSIDToBoundaryDescriptor"

76dc36f9  "AddSecureMemoryCacheCallback"

76dc3716  "AddVectoredContinueHandler"

76dc3731  "AddVectoredExceptionHandler"

76dc374d  "AdjustCalendarDate"

76dc3760  "AllocConsole"

76dc376d  "AllocateUserPhysicalPages"

76dc3787  "AllocateUserPhysicalPagesNuma"

76dc37a5  "ApplicationRecoveryFinished"

76dc37c1  "ApplicationRecoveryInProgress"

76dc37df  "AreFileApisANSI"

76dc37ef  "AssignProcessToJobObject"

76dc3808  "AttachConsole"

76dc3816  "BackupRead"

76dc3821  "BackupSeek"

76dc382c  "BackupWrite"

76dc3838  "BaseCheckAppcompatCache"

76dc3850  "BaseCheckAppcompatCacheEx"

76dc386a  "BaseCheckRunApp"

76dc387a  "BaseCleanupAppcompatCacheSupport"

76dc389a  ""

因为传参会把地址也传进去,所以加了个限制范围,过滤地址,只要内容

7.遍历IMPORT

 

0:001> dt ole32!_IMAGE_DATA_DIRECTORY 76d00160+8

   +0x000 VirtualAddress   : 0xcaa24

   +0x004 Size             : 0x1f4

0:001> ? 76d00000+0xcaa24

Evaluate expression: 1994172964 = 76dcaa24

DataDirectory[1]即为导入表,地址为76dcaa24

0:001> dt ole32!_IMAGE_IMPORT_DESCRIPTOR 76dcaa24

   +0x000 Characteristics  : 0xcaf6c

   +0x000 OriginalFirstThunk : 0xcaf6c // 输入表名(INT)

   +0x004 TimeDateStamp    : 0

   +0x008 ForwarderChain   : 0

   +0x00c Name             : 0xcaf44

   +0x010 FirstThunk       : 0x10000  // 输入地址表(IAT)

 

_IMAGE_IMPORT_DESCRIPTOR的大小为

0:001> ?? sizeof(_IMAGE_IMPORT_DESCRIPTOR)

unsigned int 0x14

 

遍历IID得到所有输入表试试

0:001> da 76d00000 + 0xcaf44

76dcaf44  "API-MS-Win-Core-RtlSupport-L1-1-"

76dcaf64  "0.dll"

0:001> dt ole32!_IMAGE_IMPORT_DESCRIPTOR 76dcaa24+0x14

   +0x000 Characteristics  : 0xcaf7c

   +0x000 OriginalFirstThunk : 0xcaf7c

   +0x004 TimeDateStamp    : 0

   +0x008 ForwarderChain   : 0

   +0x00c Name             : 0xcaf38

   +0x010 FirstThunk       : 0x10010

0:001> da 76d00000 + 0xcaf38

76dcaf38  "ntdll.dll"

分析第一个IID的IAT和INT吧:

先看INT:

IMAGE_THUNK_DATA其实就是一个DWORD,如IID一样,也是一个接一个,最后一个为NULL

第一个:

0:001> dd 0xcaf7c+76d00000 L1

76dcaf7c  000cbd98

最高位不为1(为1表示为序号输入)

指向_IMAGE_IMPORT_BY_NAME结构

0:001> .foreach(place {dd 76dcaf7c}) {r @$t0 = ${place}+76d00000+2; .if (@$t0<86d00000){da @$t0;}}

76dcbd9a  "NtCreateEvent"

76dcbdaa  "NtDuplicateObject"

76dcbdbe  "RtlConvertSidToUnicodeString"

76dcbdde  "NtNotifyChangeKey"

76dcbdf2  "RtlRunOnceInitialize"

76dcbe0a  "NtResetEvent"

76dcbe1a  "RtlValidSecurityDescriptor"

76dcbe38  "RtlOpenCurrentUser"

76dcbe4e  "strncat"

76dcbe58  "_strlwr"

76dcbe62  "NtQueryInstallUILanguage"

76dcbe7e  "RtlpConvertCultureNamesToLCIDs"

76dcbea0  "RtlpConvertLCIDsToCultureNames"

76dcbec2  "EtwEventEnabled"

76dcbed4  "RtlSetProcessPreferredUILanguage"

76dcbef4  "s"

76dcbef8  "RtlExpandEnvironmentStrings_U"

76dcbf18  "RtlUnicodeStringToInteger"

76dcbf34  "RtlLCIDToCultureName"

76dcbf4c  "RtlIdnToUnicode"

76dcbf5e  "RtlIdnToNameprepUnicode"

76dcbf78  "RtlIdnToAscii"

76dcbf88  "RtlIsNormalizedString"

76dcbfa0  "RtlNormalizeString"

76dcbfb6  "RtlIntegerToUnicodeString"

76dcbfd2  "_ui64tow"

76dcbfde  "_wtol"

76dcbfe6  "_wcslwr"

76dcbff0  "RtlUnhandledExceptionFilter"

76dcc00e  "NtTerminateProcess"

76dcc024  "wcsncpy"

76dcc02e  "wcsncmp"

76dcc038  "RtlReadThreadProfilingData"

对比loadpe

https://i-blog.csdnimg.cn/blog_migrate/b25cf7b317e6e0f1fea616b301337d94.jpeg

 

  1. windbg-!pte转换地址(ring0)

1.取得DirBase

 

kd> !process  0 0 test.exe

PROCESS 89ed6170  SessionId: 0  Cid: 0558       Peb: 7ffd9000  ParentCid: 0744

         DirBase: 0a7c0340  ObjectTable: e1e6b5a8  HandleCount:  15.

         Image: test.exe

2. 切换到指定进程

 

使用.process /i /p 89ed6170 注意一定要加/i

然后使用.process确认内核已切换到89ed6170 这个进程

然后!pte va即可!

给个清晰的示意图:

https://i-blog.csdnimg.cn/blog_migrate/77fee4ec55dc126817a6a90d6796ad69.jpeg

 

 

3.pfn对应详解

https://i-blog.csdnimg.cn/blog_migrate/16b6d891a2dfcd4cbf64b0e433c225ab.png

 

 

而!pfn更快:

 

kd> !pfn 806aeffc

PFN 006AEFFC at address 8C9B6F90//006AEFFC 为806aeffc的物理地址

flink 00000000 blink / share count 00000000 pteaddress 00000000

reference count 0000 NonCached color 0

restore pte 00000000 containing page 000000 Zeroed

kd> !pte 806aeffc

VA 806aeffc

PDE at 00000000C0602018 PTE at 00000000C0403570

contains 00000000006001E3 contains 0000000000000000

pfn 600 -GLDA–KWEV LARGE PAGE pfn 6ae

kd> db 806aeffc

806aeffc 00 00 00 00 00 00 00 00-00 00 00 00 4a 77 1d 00 …………Jw..

806af00c 2c 06 00 00 4c 70 1d 00-00 00 00 00 00 00 00 00 ,…Lp……….

806af01c 0e 78 1d 00 00 06 00 00-7c 71 1d 00 00 00 00 00 .x……|q……

806af02c 00 00 00 00 a6 78 1d 00-30 07 00 00 00 00 00 00 …..x..0…….

806af03c 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 …………….

806af04c e8 77 1d 00 d4 77 1d 00-c2 77 1d 00 ae 77 1d 00 .w…w…w…w..

806af05c a2 77 1d 00 8a 77 1d 00-72 77 1d 00 60 77 1d 00 .w…w..rw..`w..

806af06c 52 77 1d 00 f8 77 1d 00-00 00 00 00 9e 72 1d 00 Rw…w…….r..

kd> !db 006AEFFC

# 6aeffc 00 00 00 00 00 00 00 00-00 00 00 00 4a 77 1d 00 …………Jw..

3.windbg-调试技巧(函数参数的入栈顺序)

函数传参有三种方式:堆栈方式,寄存器方式,以及通过全局变量进行隐含参数的传递

 

1.堆栈方式:

 

约定类型         __cdecl(C规范)        PASCAL     stdcall       Fastcall

参数传递顺序         从右到左         从左到右         从右到左         使用寄存器和堆栈

平衡堆栈者     调用者     子程序     子程序     子程序

允许使用VARARG(不定参数)         是     否     是      

 thiscall同样是参数从右到左,this指针一般放在ecx中,不过不能显式指定,用于c++的类中

 

c/c++和MFC程序默认使用调用约定__cdecl

 

stdcall是Win32 API采用的约定方式,由于函数体本身知道传进来的参数个数,因此被调用的函数可以在返回前用ret n清理传送参数的内存栈,

 

所以test(p1,p2,p3)

 

__cdecl调用约定   PASCAL调用约定    __stdcall调用约定

push p3

push p2

push p1

call test

add esp, 0C//平衡堆栈,

这个是关键,

可以在OllyDbg中找到这个

来确定是否为C调用

0C是因为32位环境了,

堆栈操作的对象只能

是双字操作数(占4个字节)

push p1

push p2

push p3

call test //函数内平衡堆栈

 

push p3

push p2

push p1

call test//函数内平衡堆栈

函数内部调用,如test(p1,p2)

 

push p2

 

push p1

 

call test

 

{

 

push ebp //保护原有的EBP

 

mov ebp,esp//EBP指向栈顶

 

mov eax,dword ptr [ebp+0c]//调用参数2

 

mov ebx,dword ptr [ebp+08]//调用参数1

 

sub esp,8若函数要用局部变量,则要在堆栈中留出点空间

 

....

 

add esp,8//释放局部变量所占的堆栈

 

pop ebp//恢复现场ebp指针

 

ret 8,返回ret后的值为参数个数x4h

 

}

 

 

 

不理解就画个图:

 

K                起始堆栈

k-04h        P2     EBP+0Ch

k-08h        P1     EBP+08h

k-0ch         IP      EBP+04h

K-10h        保存的EBP      EBP

k-14h        局部变量1      EBP-4h

k-18h        局部变量2      EBP-8h

ESP   当前ESP指针  

 

函数返回值一般放在eax寄存器中返回,如果处理结果超过了eax寄存器,其高位就会放在edx寄存器中

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值