总体思路

在计算器执行完的最终现场,使用Windbg寻找计算结果存储地址,通过TTD回溯找地址被写入的最早时刻,结果会在几个地址拷贝传递,找到最早出现的地址,再回溯若干指令,便可达到计算乘法的地方。

调试过程

基本信息

系统:Win11, 22H2
计算器路径:C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_11.2210.0.0_x64__8wekyb3d8bbwe\CalculatorApp.exe
版本号:11.2210.0.0

过程

打开计算器

记录pid=12052

执行TTD录制

tttracer.exe要使用管理员模式运行。

tttracer.exe -ring -maxFile 2048 -out "calc_%.run" -attach 12052

乘法运算

调整到程序员hex模式,输入8547*3614,得到结果1C27638C

结束TTD

tttracer.exe -stop all

此时cmd窗口提示Ring trace dumped to C:\Users\xxxx\Desktop\calc_03.run

挂Windbg搜索地址

我用的是windbg preview版本,老版本也可以,选择Attach to process附加计算器进程,查看堆栈

0:035> !address -f:stack,heap

                                     
Mapping file section regions...
Mapping module regions...
Mapping PEB regions...
Mapping TEB and stack regions...
Mapping heap regions...
Mapping page heap regions...
Mapping other regions...
Mapping stack trace database regions...
Mapping activation context regions...

        BaseAddress      EndAddress+1        RegionSize     Type       State                 Protect             Usage
--------------------------------------------------------------------------------------------------------------------------
      28`38370000       28`3837b000        0`0000b000 MEM_PRIVATE MEM_RESERVE                                    Stack      [~12; 2f14.52e8]
...省略
     13b`d8e70000      13b`d8e80000        0`00010000 MEM_MAPPED  MEM_COMMIT  PAGE_READWRITE                     Heap       [ID: 1; Handle: 0000013bd8e70000; Type: Segment]
...省略
     13c`01a7e000      13c`01b00000        0`00082000 MEM_PRIVATE MEM_RESERVE                                    Heap       [ID: 0; Handle: 0000013bd8f30000; Type: SegmentHeap Segment]

搜索结果1C27638C的地址,得分几次搜,不然段太大提示Range error,一共搜到了4个地址。

0:035> s 13c`00000000 13c`01b00000 8c 63 27 1c
0000013c`01a5d360  8c 63 27 1c 00 00 00 00-00 00 80 40 00 00 08 00  .c'........@....
0000013c`01a5f8e0  8c 63 27 1c 00 00 00 00-00 00 00 00 00 00 0c 00  .c'.............
0:035> s 13b`f1a70000 13b`ffffa000 8c 63 27 1c
0000013b`f56953b0  8c 63 27 1c 00 00 00 00-00 00 00 00 00 00 0c 00  .c'.............
0:035> s 13b`d8e70000 13b`d9200000 8c 63 27 1c
0000013b`d902dcf0  8c 63 27 1c 00 00 00 00-00 00 00 00 00 00 0c 00  .c'.............

此时这个windbg可以放一边了。

再开一个windbg,分析TTD录制文件

选择Open trace file,打开上述calc_03.run文件。
此时有4个地址,选择哪一个跟踪回溯?应该选时间最早出现的那一个。
那么就针对上面4个地址分别执行dx指令寻找内存被操作记录。

0:001> r $t0=0000013c`01a5d360 ;r $t1=4;r $t2=1C27638C;dx -g @$cursession.TTD.Memory(@$t0,@$t0+@$t1,"rw").Where(m=>m.Value==@$t2)
======================================================================================================================================================================================================================================================================
=            = (+) EventType = (+) ThreadId = (+) UniqueThreadId = (+) TimeStart = (+) TimeEnd   = (+) AccessType = (+) IP            = (+) Address      = (+) Size = (+) Value     = (+) OverwrittenValue = (+) SystemTimeStart        = (+) SystemTimeEnd          =
======================================================================================================================================================================================================================================================================
= [0xed]     - 0x1           - 0x5208       - 0x1617             - 1F72E7:83     - 1F72E7:83     - Write          - 0x7fff3bf0142c    - 0x13c01a5d360    - 0x4      - 0x1c27638c    - 0x4                  - 2023年7月20日 15:12:54.162    - 2023年7月20日 15:12:54.162    =
= [0xee]     - 0x1           - 0x5208       - 0x1617             - 1F75BC:8F     - 1F75BC:8F     - Read           - 0x7fff055e7070    - 0x13c01a5d360    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.162    - 2023年7月20日 15:12:54.162    =
= [0xef]     - 0x1           - 0x5208       - 0x1617             - 1F89F6:83     - 1F89F6:83     - Write          - 0x7fff3bf0142c    - 0x13c01a5d360    - 0x4      - 0x1c27638c    - 0x1c27638c           - 2023年7月20日 15:12:54.162    - 2023年7月20日 15:12:54.162    =
= [0xf0]     - 0x1           - 0x5208       - 0x1617             - 1F8CDD:8F     - 1F8CDD:8F     - Read           - 0x7fff055e7070    - 0x13c01a5d360    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.162    - 2023年7月20日 15:12:54.162    =
= [0xf1]     - 0x1           - 0x5208       - 0x1617             - 1FA13D:83     - 1FA13D:83     - Write          - 0x7fff3bf0142c    - 0x13c01a5d360    - 0x4      - 0x1c27638c    - 0x1c27638c           - 2023年7月20日 15:12:54.162    - 2023年7月20日 15:12:54.162    =
= [0xf2]     - 0x1           - 0x5208       - 0x1617             - 1FA417:8F     - 1FA417:8F     - Read           - 0x7fff055e7070    - 0x13c01a5d360    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.162    - 2023年7月20日 15:12:54.162    =
= [0xf3]     - 0x1           - 0x5208       - 0x1617             - 1FB839:83     - 1FB839:83     - Write          - 0x7fff3bf0142c    - 0x13c01a5d360    - 0x4      - 0x1c27638c    - 0x1c27638c           - 2023年7月20日 15:12:54.162    - 2023年7月20日 15:12:54.162    =
= [0xf4]     - 0x1           - 0x5208       - 0x1617             - 1FBB10:8F     - 1FBB10:8F     - Read           - 0x7fff055e7070    - 0x13c01a5d360    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.162    - 2023年7月20日 15:12:54.162    =
= [0x16f]    - 0x1           - 0x5208       - 0x1617             - 2006E5:A51    - 2006E5:A51    - Write          - 0x7fff055963bb    - 0x13c01a5d360    - 0x4      - 0x1c27638c    - 0xc27638c            - 2023年7月20日 15:12:54.193    - 2023年7月20日 15:12:54.193    =
======================================================================================================================================================================================================================================================================
0:001> r $t0=0000013c`01a5f8e0 ;r $t1=4;r $t2=1C27638C;dx -g @$cursession.TTD.Memory(@$t0,@$t0+@$t1,"rw").Where(m=>m.Value==@$t2)
====================================================================================================================================================================================================================================================================
=           = (+) EventType = (+) ThreadId = (+) UniqueThreadId = (+) TimeStart = (+) TimeEnd  = (+) AccessType = (+) IP            = (+) Address      = (+) Size = (+) Value     = (+) OverwrittenValue = (+) SystemTimeStart        = (+) SystemTimeEnd          =
====================================================================================================================================================================================================================================================================
= [0xb]     - 0x1           - 0x5208       - 0x1617             - 1F5074:A8     - 1F5074:A8    - Write          - 0x7fff055e6fdc    - 0x13c01a5f8e0    - 0x4      - 0x1c27638c    - 0x0                  - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
= [0xc]     - 0x1           - 0x5208       - 0x1617             - 1F509F:8F     - 1F509F:8F    - Read           - 0x7fff055e7070    - 0x13c01a5f8e0    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
= [0xd]     - 0x1           - 0x5208       - 0x1617             - 1F625A:BF     - 1F625A:BF    - Read           - 0x7fff3bf0142a    - 0x13c01a5f8e0    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
= [0xe]     - 0x1           - 0x5208       - 0x1617             - 1F72E7:82     - 1F72E7:82    - Read           - 0x7fff3bf0142a    - 0x13c01a5f8e0    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.162    - 2023年7月20日 15:12:54.162    =
= [0xf]     - 0x1           - 0x5208       - 0x1617             - 1F89F6:82     - 1F89F6:82    - Read           - 0x7fff3bf0142a    - 0x13c01a5f8e0    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.162    - 2023年7月20日 15:12:54.162    =
= [0x10]    - 0x1           - 0x5208       - 0x1617             - 1FA13D:82     - 1FA13D:82    - Read           - 0x7fff3bf0142a    - 0x13c01a5f8e0    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.162    - 2023年7月20日 15:12:54.162    =
= [0x11]    - 0x1           - 0x5208       - 0x1617             - 1FB839:82     - 1FB839:82    - Read           - 0x7fff3bf0142a    - 0x13c01a5f8e0    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.162    - 2023年7月20日 15:12:54.162    =
= [0x12]    - 0x1           - 0x5208       - 0x1617             - 1FF001:82     - 1FF001:82    - Read           - 0x7fff3bf0142a    - 0x13c01a5f8e0    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.193    - 2023年7月20日 15:12:54.193    =
====================================================================================================================================================================================================================================================================
0:001> r $t0=0000013b`f56953b0 ;r $t1=4;r $t2=1C27638C;dx -g @$cursession.TTD.Memory(@$t0,@$t0+@$t1,"rw").Where(m=>m.Value==@$t2)
===================================================================================================================================================================================================================================================================
=          = (+) EventType = (+) ThreadId = (+) UniqueThreadId = (+) TimeStart = (+) TimeEnd  = (+) AccessType = (+) IP            = (+) Address      = (+) Size = (+) Value     = (+) OverwrittenValue = (+) SystemTimeStart        = (+) SystemTimeEnd          =
===================================================================================================================================================================================================================================================================
= [0x2]    - 0x1           - 0x5208       - 0x1617             - 1F4F14:AD     - 1F4F14:AD    - Write          - 0x7fff3bf0142c    - 0x13bf56953b0    - 0x4      - 0x1c27638c    - 0x8547               - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
===================================================================================================================================================================================================================================================================
0:001> r $t0=0000013b`d902dcf0 ;r $t1=4;r $t2=1C27638C;dx -g @$cursession.TTD.Memory(@$t0,@$t0+@$t1,"rw").Where(m=>m.Value==@$t2)
===================================================================================================================================================================================================================================================================
=          = (+) EventType = (+) ThreadId = (+) UniqueThreadId = (+) TimeStart = (+) TimeEnd  = (+) AccessType = (+) IP            = (+) Address      = (+) Size = (+) Value     = (+) OverwrittenValue = (+) SystemTimeStart        = (+) SystemTimeEnd          =
===================================================================================================================================================================================================================================================================
= [0xd]    - 0x1           - 0x5208       - 0x1617             - 1F625A:C0     - 1F625A:C0    - Write          - 0x7fff3bf0142c    - 0x13bd902dcf0    - 0x4      - 0x1c27638c    - 0x3614               - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
===================================================================================================================================================================================================================================================================

找TimeStart字段最小的那一个,就是第三个地址0000013b`f56953b0对应的时间1F4F14:AD,点击该时间点,再点[Time Travel],即可跳到这个时刻。
也可以执行!tt 指令跳转,如下:

0:001> !tt 1F4F14:AD
Setting position: 1F4F14:AD
(2f14.5208): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: 1F4F14:AD
rax=0000013bf56953b0 rbx=0000000000000001 rcx=000000001c27638c
rdx=0000013c01a5f900 rsi=0000013bf56bc1a8 rdi=0000000000000001
rip=00007fff3bf0142c rsp=0000002838efcc38 rbp=0000013c01a5f900
 r8=0000000000000004  r9=00007fff3bf0142a r10=00007fff3bf00000
r11=0000002838efcb90 r12=0000013c01a5f904 r13=0000013bf56bce88
r14=0000013bf56953b0 r15=0000000000000004
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
VCRUNTIME140_APP!memcpy+0x11c:
00007fff`3bf0142c 8908            mov     dword ptr [rax],ecx ds:0000013b`f56953b0=00008547

此时可以看到ecx是计算结果1c27638c,rax是待写入的地址。
ecx是哪里来的?通过Step Over Back往回执行,回退一次后发现是rdx地址传递过来的

VCRUNTIME140_APP!memcpy+0x11a:
00007fff`3bf0142a 8b0a            mov     ecx,dword ptr [rdx] ds:0000013c`01a5f900=1c27638c

新的地址出现了,0000013c`01a5f900,这里存了结果,再使用dx看下谁写了这个地址

0:001> r $t0=13c01a5f900 ;r $t1=4;r $t2=1C27638C;dx -g @$cursession.TTD.Memory(@$t0,@$t0+@$t1,"rw").Where(m=>m.Value==@$t2)
===================================================================================================================================================================================================================================================================
=          = (+) EventType = (+) ThreadId = (+) UniqueThreadId = (+) TimeStart = (+) TimeEnd  = (+) AccessType = (+) IP            = (+) Address      = (+) Size = (+) Value     = (+) OverwrittenValue = (+) SystemTimeStart        = (+) SystemTimeEnd          =
===================================================================================================================================================================================================================================================================
= [0x0]    - 0x1           - 0x5208       - 0x1617             - 1F4EFA:A8     - 1F4EFA:A8    - Write          - 0x7fff055e6fdc    - 0x13c01a5f900    - 0x4      - 0x1c27638c    - 0x0                  - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
= [0x1]    - 0x1           - 0x5208       - 0x1617             - 1F4F14:AC     - 1F4F14:AC    - Read           - 0x7fff3bf0142a    - 0x13c01a5f900    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
= [0x2]    - 0x1           - 0x5208       - 0x1617             - 1F4F2F:8F     - 1F4F2F:8F    - Read           - 0x7fff055e7070    - 0x13c01a5f900    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
= [0x3]    - 0x1           - 0x5208       - 0x1617             - 1F4F71:8F     - 1F4F71:8F    - Read           - 0x7fff055e7070    - 0x13c01a5f900    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
===================================================================================================================================================================================================================================================================

选择时间最早的一次,即1F4EFA:A8,当然也得看AccessType是write类型的,因为是想找写入操作,dx Memory命令里我们用了rw模式,用w模式过滤结果会少一些。

0:001> !tt 1F4EFA:A8
Setting position: 1F4EFA:A8
(2f14.5208): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: 1F4EFA:A8
rax=000000001c27638c rbx=0000013c01a5f9a0 rcx=0000000000000000
rdx=0000013c01a5f900 rsi=0000000000000001 rdi=0000013c01a66f2c
rip=00007fff055e6fdc rsp=0000002838efc900 rbp=0000002838efcdd0
 r8=0000000000000000  r9=0000000000000001 r10=00007fff3bf00000
r11=0000000000000000 r12=0000002838efcd90 r13=0000000000000001
r14=0000002838efc968 r15=000000000000005c
iopl=0         nv up ei ng nz ac po cy
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000297
CalcViewModel+0x126fdc:
00007fff`055e6fdc 8902            mov     dword ptr [rdx],eax ds:0000013c`01a5f900=00000000

此时eax有我们的计算结果,再回退执行一次

0:001> p-
Time Travel Position: 1F4EFA:A7
rax=0000013c01a5f904 rbx=0000013c01a5f9a0 rcx=0000000000000000
rdx=0000013c01a5f900 rsi=0000000000000001 rdi=0000013c01a66f2c
rip=00007fff055e6fda rsp=0000002838efc900 rbp=0000002838efcdd0
 r8=0000000000000000  r9=0000000000000001 r10=00007fff3bf00000
r11=0000000000000000 r12=0000002838efcd90 r13=0000000000000001
r14=0000002838efc968 r15=000000000000005c
iopl=0         nv up ei ng nz ac po cy
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000297
CalcViewModel+0x126fda:
00007fff`055e6fda 8b07            mov     eax,dword ptr [rdi] ds:0000013c`01a66f2c=1c27638c

又出现了新的地址0000013c`01a66f2c,存储了计算结果,针对这个地址再来一次dx,看谁写入了这里

0:001> r $t0=13c01a66f2c ;r $t1=4;r $t2=1C27638C;dx -g @$cursession.TTD.Memory(@$t0,@$t0+@$t1,"rw").Where(m=>m.Value==@$t2)
=====================================================================================================================================================================================================================================================================
=           = (+) EventType = (+) ThreadId = (+) UniqueThreadId = (+) TimeStart = (+) TimeEnd   = (+) AccessType = (+) IP            = (+) Address      = (+) Size = (+) Value     = (+) OverwrittenValue = (+) SystemTimeStart        = (+) SystemTimeEnd          =
=====================================================================================================================================================================================================================================================================
= [0x2]     - 0x1           - 0x5208       - 0x1617             - 1F4EE8:B4     - 1F4EE8:B4     - Write          - 0x7fff055ecb45    - 0x13c01a66f2c    - 0x4      - 0x1c27638c    - 0x0                  - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
= [0x3]     - 0x1           - 0x5208       - 0x1617             - 1F4EFA:A7     - 1F4EFA:A7     - Read           - 0x7fff055e6fda    - 0x13c01a66f2c    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
= [0x10]    - 0x1           - 0x5208       - 0x1617             - 1F520E:F9     - 1F520E:F9     - Read           - 0x7fff055e5375    - 0x13c01a66f2c    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
= [0x11]    - 0x1           - 0x5208       - 0x1617             - 1F5213:A4     - 1F5213:A4     - Read           - 0x7fff055e54ac    - 0x13c01a66f2c    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
= [0x15]    - 0x1           - 0x5208       - 0x1617             - 1F527F:BA     - 1F527F:BA     - Read           - 0x7fff055d10f0    - 0x13c01a66f2c    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
= [0x16]    - 0x1           - 0x5208       - 0x1617             - 1F527F:103    - 1F527F:103    - Read           - 0x7fff055e6680    - 0x13c01a66f2c    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
= [0x17]    - 0x1           - 0x5208       - 0x1617             - 1F5372:62     - 1F5372:62     - Read           - 0x7fff055e0630    - 0x13c01a66f2c    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
= [0x18]    - 0x1           - 0x5208       - 0x1617             - 1F5384:6B     - 1F5384:6B     - Read           - 0x7fff055d10f0    - 0x13c01a66f2c    - 0x4      - 0x1c27638c    -                      - 2023年7月20日 15:12:54.130    - 2023年7月20日 15:12:54.130    =
=====================================================================================================================================================================================================================================================================

找时间最早的1F4EE8:B4,Time Travel

0:001> !tt 1F4EE8:B4
Setting position: 1F4EE8:B4
(2f14.5208): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: 1F4EE8:B4
rax=000000001c27638c rbx=0000013c01a6704c rcx=000000001c27638c
rdx=000000001c27638c rsi=0000013c01a66f20 rdi=0000000000000001
rip=00007fff055ecb45 rsp=0000002838efc8c0 rbp=0000000000003614
 r8=0000000000000000  r9=0000000000000000 r10=0000013c01a66f2c
r11=0000000000000001 r12=0000000000000120 r13=0000013c01a67040
r14=0000013c01a66f30 r15=0000013c01a66890
iopl=0         nv up ei pl nz na pe nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
CalcViewModel+0x12cb45:
00007fff`055ecb45 4389048a        mov     dword ptr [r10+r9*4],eax ds:0000013c`01a66f2c=00000000

达到乘法计算现场

eax存储了我们的结果,此时往回执行就没有新的地址出现了,回溯不到20条指令即可看到乘法计算现场,经历eax-edx-rcx-r8的传递路径,到达最初的地方imul r8,rbp:

rax=0000000000003614 rbx=0000013c01a6704c rcx=0000013c01a66f2c
rdx=0000000000000000 rsi=0000013c01a66f20 rdi=0000000000000001
rip=00007fff055ecb06 rsp=0000002838efc8c0 rbp=0000000000003614
 r8=0000000000008547  r9=0000000000000000 r10=0000013c01a66f2c
r11=0000000000000001 r12=0000000000000120 r13=0000013c01a67040
r14=0000013c01a66f30 r15=0000013c01a66890
iopl=0         nv up ei pl zr na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
CalcViewModel+0x12cb06:
00007fff`055ecb06 4c0fafc5        imul    r8,rbp

r8是被乘数8547,rbp是乘数3614,分析完毕。

结论

简单来说,通过跟踪地址的操作传递路径,不断回溯,直到达到最早一次的地址写入,便可达到现场附近。
使用TTD最大的好处是固化执行路径,每个时间片都是固定的,每个时刻都是可查询的,TTD非常方便往复分析,从上帝视角窥视执行路径,极大提升分析效率。
能不能直接在录制文件里搜计算结果最早存储的地址,从而省去跟踪中间结果传递的几个步骤?这个得研究一下。

参考

https://scz.617.cn/windows/202201251528.txt
https://bbs.kanxue.com/thread-278069.htm