Twitterに書ききれないこと

イベントや技術的なことを記したい・・・

WinDbgでシステムコールをフックして引数を確認する

今回はWinDbgシステムコールをフックして,システムコール呼び出し時の引数を確認する.

環境構築は前のブログを参照.

pinksawtooth.hatenablog.com

まずはNtCreateUserProcessのアドレスの確認する.

u nt!NtCreateUserProcess:
fffff803`d04cce1c 4c8bdc          mov     r11,rsp
fffff803`d04cce1f 53              push    rbx
fffff803`d04cce20 56              push    rsi
fffff803`d04cce21 57              push    rdi
fffff803`d04cce22 4154            push    r12
fffff803`d04cce24 4155            push    r13
fffff803`d04cce26 4156            push    r14
fffff803`d04cce28 4157            push    r15

ブレークポイントを設定する.

bp fffff803`d04cce1c

再開して,プロセスを実行する. 今回はcmd.exeからnotepad.exeを起動した.

kd> g
Breakpoint 0 hit
nt!NtCreateUserProcess:
fffff803`d04cce1c 4c8bdc          mov     r11,rsp

スタックトレースを確認する. cmdからCreateProcessWが呼ばれて最終的にNtCreateUserProcessに到達したことがわかる.

kkd> kb
 # RetAddr           : Args to Child                                                           : Call Site
00 fffff802`139e2263 : fffff6fb`5fff2c80 fffff6bf`fe590250 fffff920`7bec5a65 00000000`00000000 : nt!NtCreateUserProcess
01 00007ffc`b20840ea : 00007ffc`af4473ab 00000000`00000008 000000c1`4807e5a0 00000000`00000001 : nt!KiSystemServiceCopyEnd+0x13
02 00007ffc`af4473ab : 00000000`00000008 000000c1`4807e5a0 00000000`00000001 00000000`00000000 : ntdll!NtCreateUserProcess+0xa
03 00007ffc`af484c06 : 00000000`00000012 00000000`00000020 000000c1`480c0318 000000c1`4807ede8 : KERNELBASE!CreateProcessInternalW+0xc5b
04 00007ffc`b1e8df33 : 00000000`00000000 00007ff6`665f80e8 000000c1`480cd2ee 00007ff6`00000003 : KERNELBASE!CreateProcessW+0x66
*** ERROR: Module load completed but symbols could not be loaded for cmd.exe
05 00007ff6`665d630c : 00000000`00000001 000000c1`4807f870 000000c1`480ca860 00000002`fffffa56 : KERNEL32!CreateProcessWStub+0x53
06 00000000`00000001 : 000000c1`4807f870 000000c1`480ca860 00000002`fffffa56 00000000`00000001 : cmd+0x630c
07 000000c1`4807f870 : 000000c1`480ca860 00000002`fffffa56 00000000`00000001 00000000`00080000 : 0x1
08 000000c1`480ca860 : 00000002`fffffa56 00000000`00000001 00000000`00080000 00000000`00000000 : 0x000000c1`4807f870
09 00000002`fffffa56 : 00000000`00000001 00000000`00080000 00000000`00000000 00007ff6`66610920 : 0x000000c1`480ca860
0a 00000000`00000001 : 00000000`00080000 00000000`00000000 00007ff6`66610920 000000c1`4807eed0 : 0x00000002`fffffa56
0b 00000000`00080000 : 00000000`00000000 00007ff6`66610920 000000c1`4807eed0 000000c1`4807eeb8 : 0x1
0c 00000000`00000000 : 00007ff6`66610920 000000c1`4807eed0 000000c1`4807eeb8 000000c1`c80005cd : 0x80000

引数を確認するためにスタックとレジスタを表示する.

kd> r
rax=0000000002000000 rbx=0000000000000008 rcx=0000006582ede970
rdx=0000006582ede9d8 rsi=0000000000000001 rdi=0000000000000000
rip=00007ffafbe140e0 rsp=0000006582ede888 rbp=0000006582edfdf0
 r8=0000000002000000  r9=0000000002000000 r10=0000000000000200
r11=0000006582ede860 r12=0000000000000008 r13=00000065830c9230
r14=00000065830cda90 r15=0000000000000204
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
ntdll!NtCreateUserProcess:
0033:00007ffa`fbe140e0 4c8bd1          mov     r10,rcx
kd> dq rsp
00000065`82ede888  00007ffa`f92973ab 00000000`00000008
00000065`82ede898  00000065`82edeb20 00000000`00000001
00000065`82ede8a8  00000000`00000000 00000000`00000000
00000065`82ede8b8  00000000`00000000 00000000`00000204
00000065`82ede8c8  00000065`00000001 00000065`830cda90
00000065`82ede8d8  00000065`82edebc0 00000065`82edee50
00000065`82ede8e8  00000000`00000000 00000065`82edec00
00000065`82ede8f8  00000000`00000000 00000000`00000000

x64呼び出し規約では,第1引数から第4引数まではRCX,RDX,R8,R9に格納される.第5引数以降はスタックに格納される. スタックには戻りアドレスの後,第1引数から第4引数のHome領域が確保される.このためrspから40バイト目以降が引数となる. (00000065`82ede8a8の2つめの値からが引数)

NtCreateUserProcessの引数は以下の様に定義されている.

NtCreateUserProcess(
    PHANDLE ProcessHandle,
    PHANDLE ThreadHandle,
    ACCESS_MASK ProcessDesiredAccess,
    ACCESS_MASK ThreadDesiredAccess,
    POBJECT_ATTRIBUTES ProcessObjectAttributes,
    POBJECT_ATTRIBUTES ThreadObjectAttributes,
    ULONG ProcessFlags,
    ULONG ThreadFlags,
    PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
    PPROCESS_CREATE_INFO CreateInfo,
    PPROCESS_ATTRIBUTE_LIST AttributeList
    );

つまり

1  PHANDLE ProcessHandle = rcx = 0000006582ede970 
2  PHANDLE ThreadHandle = rdx = 0000006582ede9d8
3  ACCESS_MASK ProcessDesiredAccess = r8  = 0000000002000000
4  ACCESS_MASK ThreadDesiredAccess = r9  = 0000000002000000
5  POBJECT_ATTRIBUTES ProcessObjectAttributes = 00000000`00000000
6  POBJECT_ATTRIBUTES ThreadObjectAttributes = 00000000`00000000
7  ULONG ProcessFlags = 00000204
8  ULONG ThreadFlags = 00000001
9  PRTL_USER_PROCESS_PARAMETERS ProcessParameters = 00000065`830cda90
10 PPROCESS_CREATE_INFO CreateInfo = 00000065`82edebc0
11 PPROCESS_ATTRIBUTE_LIST AttributeList = 00000065`82edee50

となる.

Pというプレフィックスがついているのはポインタとなっているため値を確認するためには,そのアドレスの値を見る必要がある.

PRTL_USER_PROCESS_PARAMETERS ProcessParameters の詳細を確認する. ProcessParametersはRTL_USER_PROCESS_PARAMETERS構造体へのポインタとなっている. RTL_USER_PROCESS_PARAMETERS構造体はWindows Vista以降で変更されている模様.

kd> dt _RTL_USER_PROCESS_PARAMETERS
ntdll!_RTL_USER_PROCESS_PARAMETERS
   +0x000 MaximumLength    : Uint4B
   +0x004 Length           : Uint4B
   +0x008 Flags            : Uint4B
   +0x00c DebugFlags       : Uint4B
   +0x010 ConsoleHandle    : Ptr64 Void
   +0x018 ConsoleFlags     : Uint4B
   +0x020 StandardInput    : Ptr64 Void
   +0x028 StandardOutput   : Ptr64 Void
   +0x030 StandardError    : Ptr64 Void
   +0x038 CurrentDirectory : _CURDIR
   +0x050 DllPath          : _UNICODE_STRING
   +0x060 ImagePathName    : _UNICODE_STRING
   +0x070 CommandLine      : _UNICODE_STRING
   +0x080 Environment      : Ptr64 Void
   +0x088 StartingX        : Uint4B
   +0x08c StartingY        : Uint4B
   +0x090 CountX           : Uint4B
   +0x094 CountY           : Uint4B
   +0x098 CountCharsX      : Uint4B
   +0x09c CountCharsY      : Uint4B
   +0x0a0 FillAttribute    : Uint4B
   +0x0a4 WindowFlags      : Uint4B
   +0x0a8 ShowWindowFlags  : Uint4B
   +0x0b0 WindowTitle      : _UNICODE_STRING
   +0x0c0 DesktopInfo      : _UNICODE_STRING
   +0x0d0 ShellInfo        : _UNICODE_STRING
   +0x0e0 RuntimeData      : _UNICODE_STRING
   +0x0f0 CurrentDirectores : [32] _RTL_DRIVE_LETTER_CURDIR
   +0x3f0 EnvironmentSize  : Uint8B
   +0x3f8 EnvironmentVersion : Uint8B
   +0x400 PackageDependencyData : Ptr64 Void
   +0x408 ProcessGroupId   : Uint4B
   +0x40c LoaderThreads    : Uint4B
   +0x060 ImagePathName    : _UNICODE_STRING
   +0x070 CommandLine      : _UNICODE_STRING

には実行されたプロセスのフルパスとコマンドライン引数が格納されている.

ImagePathNameの値を確認するため

00000065`830cda90+0x060

のメモリを見る. ImagepathNameは,UNICODE_STRING型となっている.UNICODE_STRING型は

kd> dt _UNICODE_STRING
ntdll!_UNICODE_STRING
   +0x000 Length           : Uint2B
   +0x002 MaximumLength    : Uint2B
   +0x008 Buffer           : Ptr64 Uint2B

と定義されている.

00000065`830cda90+0x060+0x008

のメモリ上にbufferのアドレスが格納されている.

バッファのアドレスにはフルパスの文字列が格納されている.

同様にコマンドライン引数も格納されている.

00000065`830cda90+0x070+0x008