winapi - 使用windbg检查Win32 ReadFile lpBuffer参数

标签 winapi windbg

我正在使用 Johnson M. Hart 所著的“Windows System Programming 4th”一书中的以下函数。熟悉 Win32 API。我也在用 Windbg 检查函数。
检查指向接收从文件读取的数据的缓冲区的参数时。我从调试器得到以下输出。有人可以解释如何使用windbg来检查lpBuffer吗?

#include "Everything.h"

#define BUF_SIZE 256      

BOOL cci_f (LPCTSTR fIn, LPCTSTR fOut, DWORD shift)
{
    HANDLE hIn, hOut;
    DWORD nIn, nOut, iCopy;
    BYTE buffer [BUF_SIZE], bShift = (BYTE)shift;
    BOOL writeOK = TRUE;

    hIn = CreateFile (fIn, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hIn == INVALID_HANDLE_VALUE) return FALSE;

    hOut = CreateFile (fOut, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hOut == INVALID_HANDLE_VALUE) {
        CloseHandle(hIn);
        return FALSE;
    }

    while (writeOK && ReadFile (hIn, buffer, BUF_SIZE, &nIn, NULL) && nIn > 0) {
        for (iCopy = 0; iCopy < nIn; iCopy++)
            buffer[iCopy] = buffer[iCopy] + bShift;
        writeOK = WriteFile (hOut, buffer, nIn, &nOut, NULL);
    }

    CloseHandle (hIn);
    CloseHandle (hOut);

    return writeOK;
}

0:000> bp kernel32!readfile
0:000> g
Breakpoint 1 hit
eax=00000000 ebx=00000000 ecx=0018bf0c edx=00000030 esi=00000030 edi=0018ff20
eip=77383f11 esp=0018bddc ebp=0018be20 iopl=0         nv up ei ng nz ac po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000293
kernel32!ReadFile:
77383f11 ff25ec093877    jmp     dword ptr [kernel32!_imp__ReadFile (773809ec)] ds:002b:773809ec={KERNELBASE!ReadFile (75efdc4a)}
0:000> k
ChildEBP RetAddr  
0018be20 00411551 kernel32!ReadFile
0018ff44 00411b50 cpW!main+0x181 [c:\microsoft_press\wsp4_examples\chaptr01\cpw.c @ 31]
0018ff88 7738338a cpW!__tmainCRTStartup+0x122 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 555]
0018ff94 779b9f72 kernel32!BaseThreadInitThunk+0xe
0018ffd4 779b9f45 ntdll!__RtlUserThreadStart+0x70
0018ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> dd ebp
0018be20  0018ff44 00411551 00000030 0018bf0c
0018be30  00004000 0018ff20 00000000 0041757c
0018be40  00000001 00000000 cccccccc cccccccc
0018be50  cccccccc cccccccc cccccccc cccccccc
0018be60  cccccccc cccccccc cccccccc cccccccc
0018be70  cccccccc cccccccc cccccccc cccccccc
0018be80  cccccccc cccccccc cccccccc cccccccc
0018be90  cccccccc cccccccc cccccccc cccccccc
0:000> da 0018bf0c
0018bf0c  "................................"
0018bf2c  "................................"
0018bf4c  "................................"
0018bf6c  "................................"
0018bf8c  "................................"
0018bfac  "................................"
0018bfcc  "................................"
0018bfec  "................................"
0018c00c  "................................"
0018c02c  "................................"
0018c04c  "................................"
0018c06c  "................................"

建议后的其他调试输出如下。
0:000> lm
start    end        module name
00400000 0040a000   cci        (deferred)             
71580000 71656000   MSVCR110   (deferred)             
71660000 71703000   MSVCR90    (deferred)             
72660000 72666000   Utility_4_0   (deferred)             
76630000 76677000   KERNELBASE   (deferred)             
76950000 76a60000   kernel32   (deferred)             
771d0000 77350000   ntdll      (pdb symbols)          c:\symbol\wntdll.pdb\69DDFBCBBC14421D8CB974F8EDC414102\wntdll.pdb
0:000> .sympath+ C:\Microsoft_Press\WSP4_Examples\Projects2008\cci\Debug
Symbol search path is: SRV*c:\symbol*http://msdl.microsoft.com/download/symbols;C:\Microsoft_Press\WSP4_Examples\Projects2008\cci\Debug
Expanded Symbol search path is: srv*c:\symbol*http://msdl.microsoft.com/download/symbols;c:\microsoft_press\wsp4_examples\projects2008\cci\debug

************* Symbol Path validation summary **************
Response                         Time (ms)     Location
Deferred                                       SRV*c:\symbol*http://msdl.microsoft.com/download/symbols
OK                                             C:\Microsoft_Press\WSP4_Examples\Projects2008\cci\Debug
0:000> bp cci!main
*** WARNING: Unable to verify checksum for cci.exe
0:000> g
Breakpoint 0 hit
eax=71648634 ebx=00000000 ecx=0048e198 edx=00000000 esi=00000001 edi=00000000
eip=00401020 esp=0018ff4c ebp=0018ff88 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
cci!main:
00401020 55              push    ebp
0:000> bp kernel32!Readfile
0:000> g
Breakpoint 1 hit
eax=00000000 ebx=00000000 ecx=0018fd24 edx=0000003c esi=0000003c edi=0018fe44
eip=76963f11 esp=0018fbdc ebp=0018fc20 iopl=0         nv up ei ng nz ac po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000293
kernel32!ReadFile:
76963f11 ff25ec099676    jmp     dword ptr [kernel32!_imp__ReadFile (769609ec)] ds:002b:769609ec={KERNELBASE!ReadFile (7663dc4a)}
0:000> k
ChildEBP RetAddr  
0018fc20 004011f3 kernel32!ReadFile
0018fe68 004010a3 cci!cci_f+0xe3 [c:\microsoft_press\wsp4_examples\chaptr02\cci_f.c @ 29]
0018ff48 00401765 cci!main+0x83 [c:\microsoft_press\wsp4_examples\chaptr02\cci.c @ 24]
0018ff88 7696338a cci!__tmainCRTStartup+0xfd [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 536]
0018ff94 77209f72 kernel32!BaseThreadInitThunk+0xe
0018ffd4 77209f45 ntdll!__RtlUserThreadStart+0x70
0018ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> r esp
esp=0018fbdc
0:000> dd 0018fbdc
0018fbdc  76963ee7 0000003c 0018fd24 00000100
0018fbec  0018fe44 00000000 988c6ffa 0018fe68
0018fbfc  0018fc3c 00000000 769653d0 0018fbf4
0018fc0c  0018fc3c 0018ff78 76a04643 ee02ad2a
0018fc1c  fffffffe 0018fe68 004011f3 0000003c
0018fc2c  0018fd24 00000100 0018fe44 00000000
0018fc3c  0018ff48 0018fe7c 00000000 cccccccc
0018fc4c  cccccccc cccccccc cccccccc cccccccc
0:000> !handle 0000003c f
Handle 3c
  Type          File
  Attributes    0
  GrantedAccess 0x120089:
         ReadControl,Synch
         Read/List,ReadEA,ReadAttr
  HandleCount   2
  PointerCount  19
  No Object Specific Information available
0:000> da 0018fd24
0018fd24  "................................"
0018fd44  "................................"
0018fd64  "................................"
0018fd84  "................................"
0018fda4  "................................"
0018fdc4  "................................"
0018fde4  "................................"
0018fe04  "................................"
0018fe24  "................................"
0018fe44  ""
0:000> r ebp
ebp=0018fc20
0:000> dd 0018fc20
0018fc20  0018fe68 004011f3 0000003c 0018fd24
0018fc30  00000100 0018fe44 00000000 0018ff48
0018fc40  0018fe7c 00000000 cccccccc cccccccc
0018fc50  cccccccc cccccccc cccccccc cccccccc
0018fc60  cccccccc cccccccc cccccccc cccccccc
0018fc70  cccccccc cccccccc cccccccc cccccccc
0018fc80  cccccccc cccccccc cccccccc cccccccc
0018fc90  cccccccc cccccccc cccccccc cccccccc
0:000> da 0018fd24
0018fd24  "................................"
0018fd44  "................................"
0018fd64  "................................"
0018fd84  "................................"
0018fda4  "................................"
0018fdc4  "................................"
0018fde4  "................................"
0018fe04  "................................"
0018fe24  "................................"
0018fe44  ""

转储 Kernel32!Writefile lBuffer 显示要写入文件的数据。我不清楚为什么 kernel32!ReadFile 没有显示 lpBuffer 参数中的数据。
0:000> bp kernel32!writefile
0:000> g
Breakpoint 2 hit
eax=00000040 ebx=00000000 ecx=0018fe38 edx=00000000 esi=0018fc3c edi=0018fe68
eip=769617ad esp=0018fc08 ebp=0018fc20 iopl=0         nv up ei ng nz ac po cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000293
kernel32!WriteFile:
769617ad ff25e4099676    jmp     dword ptr [kernel32!_imp__WriteFile (769609e4)] ds:002b:769609e4={KERNELBASE!WriteFile (7663ddbc)}
0:000> k
ChildEBP RetAddr  
0018fc20 0040125b kernel32!WriteFile
0018fe68 004010a3 cci!cci_f+0x14b [c:\microsoft_press\wsp4_examples\chaptr02\cci_f.c @ 36]
0018ff48 00401765 cci!main+0x83 [c:\microsoft_press\wsp4_examples\chaptr02\cci.c @ 24]
0018ff88 7696338a cci!__tmainCRTStartup+0xfd [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 536]
0018ff94 77209f72 kernel32!BaseThreadInitThunk+0xe
0018ffd4 77209f45 ntdll!__RtlUserThreadStart+0x70
0018ffec 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> dd 0018fc20
0018fc20  0018fe68 0040125b 00000040 0018fd24
0018fc30  00000100 0018fe38 00000000 0018ff48
0018fc40  0018fe7c 00000000 cccccccc cccccccc
0018fc50  cccccccc cccccccc cccccccc cccccccc
0018fc60  cccccccc cccccccc cccccccc cccccccc
0018fc70  cccccccc cccccccc cccccccc cccccccc
0018fc80  cccccccc cccccccc cccccccc cccccccc
0018fc90  cccccccc cccccccc cccccccc cccccccc
0:000> da 0018fd24
0018fd24  "9:(86:::@@98<?8:@;<A<;..9:(86:::"
0018fd44  "@@98<?8:@;<A<;..9:(86:::@@98<?8:"
0018fd64  "@;<A<;..9:(86:::@@98<?8:@;<A<;.."
0018fd84  "9:(86:::@@98<?8:@;<A<;..9:(86:::"
0018fda4  "@@98<?8:@;<A<;..9:(86:::@@98<?8:"
0018fdc4  "@;<A<;..9:(86:::@@98<?8:@;<A<;.."
0018fde4  "9:(86:::@@98<?8:@;<A<;..9:(86:::"
0018fe04  "@@98<?8:@;<A<;..9:(86:::@@98<?8:"
0018fe24  "........"

感谢社区提供的洞察力。我可以通过首先在 Kernel32!ReadFile 上设置断点来查看 lpBuffer 中的数据。然后执行 gu(gu 命令使目标执行,直到当前函数完成)。此后我可以转储缓冲区。现在显示了我感兴趣的数据。

最佳答案

BOOL WINAPI ReadFile(
  _In_         HANDLE hFile,
  _Out_        LPVOID lpBuffer,
  _In_         DWORD nNumberOfBytesToRead,
  _Out_opt_    LPDWORD lpNumberOfBytesRead,
  _Inout_opt_  LPOVERLAPPED lpOverlapped
);

当您有 broken on ReadFile lpBuffer将包含 rubbish/ garbage/ zeros/ or pre initialised content based on how you allocated and initialised the buffer这个缓冲区将填满文件 only after you return from the API 的内容退出函数使用 gu (goup)并检查缓冲区( save the address of buffer first 用于稍后检查 address of buffer should be at @esp+08 当您在 32 位系统上的 kernel32.dll 中的 ReadFile 上损坏时
the walk through下面 creates a new file in current directory然后 writes to it然后 resets the file position用于读取文件开头 reads the fileprints the content to stdout并在 Closing the handle 之后退出.
  • cdb是控制台模式windbg
  • -c switch 接受命令在事件上执行
  • g main执行文件直到 main 以避免无趣的中断
    阅读文件
  • bp kernel32!ReadFile在 API 上设置断点
  • g to execute the file以便它在我们的断点处中断
  • bc * to clear any breakpoints (建议养成这个习惯的时候
    脚本)
  • r $t0 = poi(@esp+8)将指针保存到 lpBuffer
  • poi(@esp+0)总是返回地址
  • poi(@esp+4)在函数启动时中断时总是第一个参数
    在 32 位系统中。
  • .echo is to output a comment .
  • db @$t0 l20打印 lpBuffer 的前 20 个字节 prior to执行 ReadFile()
  • gu是去组
  • .echo is to output a comment .
  • db @$t0 l20打印 lpBuffer 的前 20 个字节 post执行 ReadFile()
  • g;q is to continue and quit执行完文件


  • 读取文件>输入 readfile.cpp & %compile% readfile.cpp & readfile.exe
    #include <stdio.h>
    #include <Windows.h>
    int main(void)    {
        char writein[] = {"Iam going to write me in\n"};
        char readin [] = {"Iam rubbish Iam garbage Readfile will clean me up\n" };
        DWORD bytesreadoutin = 0;
        BOOL result = FALSE;
        HANDLE hFile = CreateFileA("mynewtxt.txt",GENERIC_ALL,FILE_SHARE_WRITE |
            FILE_SHARE_READ,NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
        if (INVALID_HANDLE_VALUE != hFile) {
            if ((result = WriteFile(
                hFile,writein,sizeof(writein),&bytesreadoutin,NULL)) == TRUE ) {
                if (bytesreadoutin == sizeof(writein))  {
                    if ( INVALID_SET_FILE_POINTER != SetFilePointer(
                        hFile,NULL,NULL,FILE_BEGIN) ) {
                        if (( result = ReadFile(
                            hFile,readin,sizeof(writein),&bytesreadoutin,
                            NULL))== TRUE)  {
                            printf(readin);
                        }
                    }
                }
            }
            CloseHandle(hFile);
        }
        return 0;
    }Setting environment for using Microsoft Visual Studio 2010 x86 tools.
    readfile.cpp
    Press any key to continue . . .
    I am going to write me in
    

    带风袋

    readfile>cdb -c "g main;bp kernel32!ReadFile;g;bc *;r $t0 = poi(@esp+8);.echo =============缓冲内容预读文件================;db @$t0 l20;gu;.echo ======================缓冲区内容 post readfile==================;db @$t0 l20;g;q"readfile.exe
    ntdll!DbgBreakPoint:
    7c90120e cc              int     3
    0:000> cdb: Reading initial command 'g main;bp kernel32!ReadFile;g;bc *;r $t0 =
    poi(@esp+8);.echo =============buffer contents pre readfile================;db @
    $t0 l20;gu;.echo ======================buffer contents post readfile============
    =====;db @$t0 l20;g;q'
    
    Breakpoint 0 hit
    =============buffer contents pre readfile================
    0013ff34  49 20 61 6d 20 72 75 62-62 69 73 68 20 49 20 61  I am rubbish I a
    0013ff44  6d 20 67 61 72 62 61 67-65 49 20 77 69 6c 6c 20  m garbageI will
    ======================buffer contents post readfile=================
    0013ff34  49 20 61 6d 20 67 6f 69-6e 67 20 74 6f 20 77 72  I am going to wr
    0013ff44  69 74 65 20 6d 65 20 69-6e 0a 00 77 69 6c 6c 20  ite me in..will
    I am going to write me in
    quit:
    

    记录所有 ReadFile 调用 write a simple script使用 .block {} 中的所有命令和 set a conditional breakpoint like bp kernel32!ReadFile "$$>a< X:\\blah.ext"
    请注意 ReadFile 是 Very Busy Api总的来说,你 do not
    设置 permanent breaks in busy apis因为这可能会导致性能非常差
    或 session 中不受欢迎的缓慢,并且在调试时间相关代码的问题时可能会引入严重的问题

    脚本文件内容
    0:004> .shell -ci " " type c:\\readfile.txt
    .block {
    r $t0 = poi(@esp+0x8);
    .echo ========================================pre&post===========================
    db @$t0 l10;
    gu;
    db @$t0 l10;
    g;
    }.shell: Process exited
    

    结果
    0:002> $$ start of logging ReadFile 
    0:002> bl
     0 e 7c801812     0001 (0001)  0:**** kernel32!ReadFile "$$>a< c:\\readfile.txt"
    0:002> .bpcmds
    bp0 0x7c801812  "$$>a< c:\\readfile.txt";
    0:002> g
    ========================================pre&post===========================
    0011fa10  00 00 00 00 00 00 00 00-60 00 00 00 00 00 00 00  ........`.......
    0011fa10  49 54 53 46 03 00 00 00-60 00 00 00 01 00 00 00  ITSF....`.......
    ========================================pre&post===========================
    001271d8  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    001271d8  49 54 53 50 01 00 00 00-54 00 00 00 0a 00 00 00  ITSP....T.......
    ========================================pre&post===========================
    000e9038  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    000e9038  50 4d 47 4c 10 0b 00 00-00 00 00 00 ff ff ff ff  PMGL............
    ========================================pre&post===========================
    009eed38  f0 f9 11 00 a8 ed 9e 00-fd f3 e2 65 f0 f9 11 00  ...........e....
    009eed38  1e 00 11 00 a8 ed 9e 00-fd f3 e2 65 f0 f9 11 00  ...........e....
    ========================================pre&post===========================
    0011ef42  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    0011ef42  02 00 0c 00 55 00 6e 00-63 00 6f 00 6d 00 70 00  ....U.n.c.o.m.p.
    ========================================pre&post===========================
    009ef018  50 0a 15 00 d8 6b 3d 00-34 f0 9e 00 6c f0 9e 00  P....k=.4...l...
    009ef018  03 00 00 00 d8 6b 3d 00-34 f0 9e 00 6c f0 9e 00  .....k=.4...l...
    ========================================pre&post===========================
    

    关于winapi - 使用windbg检查Win32 ReadFile lpBuffer参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25100756/

    相关文章:

    c++ - Ole 拖放故障排除

    multithreading - WAIT_ABANDONED_0 何时返回

    .net - WinDbg内存分析

    windows - 无法使用选项上的 bcdedit/debug 启动 Windows 7(32 位)

    c++ - 调试 Win32 应用程序挂起

    windbg - 为什么windbg中的!dumpvc可以dump出数组元素?

    python - 如何在Windows中使用python以用户身份创建进程?

    C++ Win32 通过电子邮件或网络浏览器发送消息

    windows - 如何在 Delphi 中枚举另一个进程的窗口?

    debugging - 在故障转储中获取堆栈的时间戳