windbg記憶體斷點學習總結
阿新 • • 發佈:2019-02-08
Windbg中使用查詢記憶體並設定訪問斷點
http://www.cnblogs.com/SkyMouse/archive/2012/06/06/2538745.html在windbg中通過s 命令在記憶體中查詢字串或者關鍵位元組碼資訊
0:005> s -u 00c00000 L1000000 "你好 20:15 2012/6/620:15 2012/6/6"
01960d28 4f60 597d 0020 0032 0030 003a 0031 0035 `O}Y .2.0.:.1.5.
檢視記憶體01960d28
01960d28 00 00 00 00 00 00 00 00 30 00 3a 00 31 00 35 00 20 00 ........0.:.1.5. .
01960d3a 32 00 30 00 31 00 32 00 2f 00 36 00 2f 00 36 00 32 00 2.0.1.2./.6./.6.2.
01960d4c 30 00 3a 00 31 00 35 00 20 00 32 00 30 00 31 00 32 00 0.:.1.5. .2.0.1.2.
01960d5e 2f 00 36 00 2f 00 36 00 00 00 00 00 00 00 00 00 00 00 /.6./.6...........
找到內容之後通過ba設定訪問斷點在任何函式訪問該記憶體時將會中斷
0:005> ba r4 01960d28
0:005> bl
0 du 0001 (0001) (@@masm(`ItemOperation.cpp:60+`))
1 e 01960d28 r 4 0001 (0001) 0:****
2 e 771c3540 0001 (0001) 0:**** ntdll!DbgBreakPoint
如此在程式訪問該地址時將會中斷到偵錯程式
0:005> g
Breakpoint 1 hit
eax=019607d0 ebx=00000023 ecx=00000003 edx=0000002c esi=019607d0 edi=01960cd0
eip=76d29c9c esp=000fefa4 ebp=000fefa8 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
msvcrt!_VEC_memcpy+0x125:
76d29c9c 660f7f4760 movdqa xmmword ptr [edi+60h],xmm0 ds:0023:01960d30=003100300032002000350031003a0030
當然也可以根據自身需要查詢相應的其他內容來實現設定相應的訪問斷點
========
誰動了我的指標?--記一次WINDBG記憶體斷點的使用
寫驅動的時候有個地方老是藍屏,看了dump發現數據被非法篡改了.
資料初始化如下
if(record_set_ptr != NULL )
{
record_set_ptr->look_aside_pool_ptr = g_user_control_context.look_aside_pools[type] ;
record_set_ptr->type = type ;
record_set_ptr->buffer_size = notify_count * unit_size_of ;
record_set_ptr->units_count = notify_count ;
record_set_ptr->complete_count = 0 ;
}
然後在呼叫ExFreeToNPagedLookasideList傳入record_set_ptr->look_aside_pool_ptr 的時候掛了,發現record_set_ptr->look_aside_pool_ptr已經被改了.
為了跟蹤資料在哪裡被修改了,先在資料初始化的地方下斷,然後記下record_set_ptr->look_aside_pool_ptr 的地址:0x85c16018
對這個記憶體下個斷點
1: kd> ba w4 85c16018
w表示在寫入時斷下,4表示監控範圍,單位是位元組
整個命令的意思就是讓偵錯程式在系統寫入記憶體85c16018-85c1601b這個地址範圍的時候中斷
OK,命令下完,F5一下就立馬斷下來了
1: kd> g
Breakpoint 3 hit
nt!memcpy+0x33:
8053b583 f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
此時edi的值: 0x85c16018
最後看一下函式堆疊,發現是字串拷貝越界覆蓋了後面的資料....
後面又想到,出錯時record_set_ptr->look_aside_pool_ptr 的值是0x005c0065
這麼明顯的字串特徵竟然沒意識到....一看出錯值就應該知道是字串覆蓋造成的.....
posted on 2012-01-03 15:07 __ay 閱讀(3020) 評論(3) 編輯 收藏 引用 所屬分類: Debugging
Feedback
# re: 誰動了我的指標?--記一次windbg記憶體斷點的使用 2012-01-05 09:33 zuhd
和樓主分享一下:
一般遇到這種需要下記憶體斷點的除錯,我可能會先檢查程式碼,應該會有90%的概率是越界造成的,確定該記憶體是在堆還是棧,然後排查該變數上下的兩個變數,基本都能找到,呵呵。請問樓主是UESTC的嗎? 回覆 更多評論
# re: 誰動了我的指標?--記一次windbg記憶體斷點的使用 2012-01-05 13:30 __ay
呵呵 你也是UESTC的?不過我已經畢業了
當然如果越界的時候能直接引發崩潰,那麼看程式碼直接就能解決問題
但是在越界讀寫不引發crash,直到引用被覆蓋的資料的時候才崩潰,如果這個時候程式碼中很難定位到被覆蓋資料是什麼時候寫的,那應該用記憶體斷點會比較好了@zuhd
========
windbg memory breakpoint 記憶體斷點
ba (Break on Access)
[cpp] view plain copy 在CODE上檢視程式碼片派生到我的程式碼片
kd> ba i4 3f8
Kernel-Mode
ba[ID] Access Size [Options] [Address [Passes]] ["CommandString"]
Access
Specifies the type of access that satisfies the breakpoint. This parameter can be one of the following values.
OptionAction
e (execute)
Breaks into the debugger when the CPU retrieves an instruction from the specified address.
r(read/write)
Breaks into the debugger when the CPU reads or writes at the specified address.
w (write)
Breaks into the debugger when the CPU writes at the specified address.
i (i/o)
(Microsoft Windows XP and later versions, kernel mode only, x86-based systems only) Breaks into the debugger when the I/O port at the specified Address is accessed.
Size
Specifies the size of the location, in bytes, to monitor for access. On an x86-based processor, this parameter can be 1, 2, or 4. However, if Access equals e, Sizemust be 1.
On an x64-based processor, this parameter can be 1, 2, 4, or 8. However, if Access equals e, Size must be 1.
https://msdn.microsoft.com/en-us/library/windows/hardware/ff538165(v=vs.85).aspx
========
windbg --記憶體資料斷點
ba (Break on Access)
The ba command sets a data breakpoint. This breakpoint is triggered when the specified memory is accessed.
Syntax
User-Mode
[~Thread] ba[ID] Access Size [Options] [Address [Passes]] ["CommandString"]
Kernel-Mode
ba[ID] Access Size [Options] [Address [Passes]] ["CommandString"]
Parameters
Thread
Specifies the thread that the breakpoint applies to. For more information about syntax, see Thread Syntax. You can specify threads only in user mode.
ID
Specifies an optional number that identifies the breakpoint. If you do not specify ID, the first available breakpoint number is used. You cannot add space between ba and the ID number. Each processor supports only a limited number of data breakpoints. But there is no restriction on the value of the ID number. If you enclose ID in square brackets ([]), ID can include any expression. For more information about the syntax, see Numerical Expression Syntax.
Access
Specifies the type of access that satisfies the breakpoint. This parameter can be one of the following values.
OptionAction
e (execute)Breaks into the debugger when the CPU retrieves an instruction from the specified address.
r (read/write)Breaks into the debugger when the CPU reads or writes at the specified address.
w (write)Breaks into the debugger when the CPU writes at the specified address.
i (i/o)(Microsoft Windows XP and later versions, kernel mode only, x86-based systems only) Breaks into the debugger when the I/O port at the specified Address is accessed.
You cannot add space between Access and Size.
Note On Windows Server 2003 with Service Pack 1 (SP1), on an Itanium-based computer that uses WOW64 to emulate x86, data breakpoints do not work with the execute option but they do work with the read and write options.
Size
Specifies the size of the location, in bytes, to monitor for access. On an x86-based processor, this parameter can be 1, 2, or 4. However, if Access equals e, Size must be 1.
On an x64-based processor, this parameter can be 1, 2, 4, or 8. However, if Access equals e, Size must be 1.
On an Itanium-based processor, this parameter can be any power of 2, from 1 to 0x80000000.
You cannot add space between Access and Size.
Options
Specifies breakpoint options. You can use any number of the following options, except as indicated:
/1
Creates a "one-shot" breakpoint. After this breakpoint is triggered, the breakpoint is permanently removed from the breakpoint list.
/f PredNum
(Itanium only, user mode only) Specifies a predicate number. The breakpoint is predicated with the corresponding predicate register (for example, bp /f 4 address sets a breakpoint that is predicated with the p4 predicate register). For more information about predicate registers, see Itanium Architecture.
/p EProcess
(Kernel mode only) Specifies a process that is associated with this breakpoint. EProcess should be the actual address of the EPROCESS structure, not the PID. The breakpoint is triggered only if it is encountered in the context of this process.
/t EThread
(Kernel mode only) Specifies a thread that is associated with this breakpoint. EThread should be the actual address of the ETHREAD structure, not the thread ID. The breakpoint is triggered only if it is encountered in the context of this thread. If you use /p EProcess and /t EThread , you can enter them in either order.
/c MaxCallStackDepth
Causes the breakpoint to be active only when the call stack depth is less than MaxCallStackDepth. You cannot combine this option together with /C.
/C MinCallStackDepth
Causes the breakpoint to be active only when the call stack depth is larger than MinCallStackDepth. You cannot combine this option together with /c.
Address
Specifies any valid address. If the application accesses memory at this address, the debugger stops execution and displays the current values of all registers and flags. This address must be an offset and suitably aligned to match the Size parameter. (For example, if Size is 4, Address must be a multiple of 4.) If you omit Address, the current instruction pointer is used. For more information about the syntax, see Address and Address Range Syntax.
Passes
Specifies the number of times the breakpoint is passed by until it activates. This number can be any 16-bit value. The number of times the program counter passes through this point without breaking is one less than the value of this number. Therefore, omitting this number is the same as setting it equal to 1. Note also that this number counts only the times that the application executes past this point. Stepping or tracing past this point does not count. After the full count is reached, you can reset this number only by clearing and resetting the breakpoint.
CommandString
Specifies a list of commands to execute every time that the breakpoint is encountered the specified number of times. These commands are executed only if the breakpoint is hit after you issue a g (Go) command, instead of after a t (Trace) or p (Step) command. Debugger commands in CommandString can include parameters.
You must enclose this command string in quotation marks, and you should separate multiple commands by semicolons. You can use standard C control characters (such as \n and \"). Semicolons that are contained in second-level quotation marks (\") are intepreted as part of the embedded quoted string.
This parameter is optional
Environment
ModesUser mode, kernel mode
TargetsLive debugging only
PlatformsAll
Comments
The debugger uses the ID number to refer to the breakpoint in later bc (Breakpoint Clear), bd (Breakpoint Disable), and be (Breakpoint Enable), commands. Use the bl (Breakpoint List) command to see the ID numbers that are associated with all currently set breakpoints.
The ba command provides the same functionality that the debug registers provide. You can break execution when the particular memory location is read from, written to, or executed.
The breakpoint is satisfied only when the access occurs at the given address and for the specified number of bytes. If the memory that is accessed overlaps the specified area to monitor, the breakpoint is not satisfied.
Although the size is required for all breakpoint types, an execute breakpoint is satisfied only if the address is the first byte in the instruction.
When you debug a multiprocessor system in kernel mode, breakpoints that you set by using bp (Set Breakpoint) or ba apply to all processors. For example, if the current processor is 3 and you type ba e1 MemoryAddress to put a breakpoint at MemoryAddress, any processor (not only processor 3) that executes at that address causes a breakpoint trap.
You cannot set the initial breakpoint in a user-mode process by using the ba command.
You cannot create multiple breakpoints at the same address that differ only in their CommandString values. However, you can create multiple breakpoints at the same address that have different restrictions (for example, different values of the /p, /t, /c, and /C options).
When you debug in kernel mode, the target computer distinguishes between user-mode and kernel-mode data breakpoints. A user-mode data breakpoint cannot affect kernel execution or memory access. A kernel-mode data breakpoint might affect user-mode execution or memory access, depending on whether the user-mode code is using the debug register state and whether there is a user-mode debugger that is attached.
To apply the current process' existing data breakpoints to a different register context, use the .apply_dbp (Apply Data Breakpoint to Context) command.
The following examples show the ba command. The following command sets a breakpoint for read access on 4 bytes of the variable myVar.
0:000> ba r4 myVar
The following command adds a breakpoint on all serial ports with addresses from 0x3F8 through 0x3FB. This breakpoint is triggered if anything is read or written to these ports.
kd> ba i4 3f8
========
兩次記憶體斷點法尋找OEP
http://www.programlife.net/twice-breakpoint-find-oep.html逆向過程中通過會遇到脫殼的過程,而脫殼的方式有有多重,如果手工脫殼,需要找到OEP。
所謂“兩次記憶體斷點法尋找OEP”,按照《加密與解密*第三版》上的解釋來說,就是這樣的。
一般的外殼會依次對.text、.rdata、.data、.rsrc區塊進行解壓(解密)處理,所以,可以先在.rdata、.data等區塊下記憶體訪問斷點,中斷後,此時程式碼已解壓,接著再對程式碼段(.text)下記憶體訪問斷點,即可到達OEP。
我個人的理解是所有節區都解壓完畢之後,然後程式的執行流會轉移到OEP,這個時候自然回去訪問相應的程式碼,所以就會斷下;實際操作的時候還需要多一個跟蹤步驟。
這裡以一個UPX加殼的程式為例:
首先OD載入程式,Alt + M開啟記憶體對映檢視,找到主模組的資料段或者資源段F2下訪問中斷,如圖。
對資料段或者資源段下F2訪問中斷
然後F9執行程式,會自動斷下,再次Alt + M開啟記憶體對映檢視,找到程式碼段F2下訪問中斷,如圖。
對程式碼段下F2訪問中斷
之後F9執行,會再次斷下。這個時候仍然Alt + M開啟記憶體對映檢視,觀察一下主模組的區塊。
0040BA75 8D8430 58B00000 LEA EAX,DWORD PTR DS:[EAX+ESI+B058]
0040BA7C 01F3 ADD EBX,ESI
0040BA7E 50 PUSH EAX
0040BA7F 83C7 08 ADD EDI,8
0040BA82 FF96 94B00000 CALL DWORD PTR DS:[ESI+B094] ; KERNEL32.LoadLibraryA
0040BA88 95 XCHG EAX,EBP
0040BA89 8A07 MOV AL,BYTE PTR DS:[EDI]
0040BA8B 47 INC EDI
0040BA8C 08C0 OR AL,AL
0040BA8E ^ 74 DC JE SHORT 0040BA6C
0040BA90 89F9 MOV ECX,EDI
Memory map, 專案 18
地址=00401000
大小=00008000 (32768.)
屬主=UpxDemo 00400000
區段=UPX0
型別=映像 01001002
訪問=R
初始訪問=RWE
Memory map, 專案 19
地址=00409000
大小=00003000 (12288.)
屬主=UpxDemo 00400000
區段=UPX1
包含=SFX,程式碼
型別=映像 01001002
訪問=R
初始訪問=RWE
看到UPX0和UPX1到底哪一個是真實的程式碼塊呢?需要試一下。對於UPX0,VA的範圍是00401000~00409000,對於UPX1,VA的範圍是00409000~0040C000。可以在OD的命令列中執行tc eip<00409000,按Enter執行,發現來到了OEP了。(同樣可以測試tc eip<0040C000,但得到的不是OEP)。
00401120 55 PUSH EBP
00401121 8BEC MOV EBP,ESP
00401123 6A FF PUSH -1
00401125 68 B8504000 PUSH 004050B8
0040112A 68 EC1D4000 PUSH 00401DEC
0040112F 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
00401135 50 PUSH EAX
00401136 64:8925 0000000>MOV DWORD PTR FS:[0],ESP
0040113D 83EC 58 SUB ESP,58
00401140 53 PUSH EBX
00401141 56 PUSH ESI
00401142 57 PUSH EDI
00401143 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
00401146 FF15 28504000 CALL DWORD PTR DS:[405028] ; KERNEL32.GetVersion
0040114C 33D2 XOR EDX,EDX
0040114E 8AD4 MOV DL,AH
00401150 8915 14854000 MOV DWORD PTR DS:[408514],EDX
00401156 8BC8 MOV ECX,EAX
00401158 81E1 FF000000 AND ECX,0FF
0040115E 890D 10854000 MOV DWORD PTR DS:[408510],ECX
00401164 C1E1 08 SHL ECX,8
附:
TC (Trace in till condition)跟蹤進入直到條件
更多參考:http://www.pediy.com/bbshtml/BBS5/pediy50401.htm
========