一、斷點
調試很重要一點是下斷點,看看IDA提供的功能,本來已經和WinDbg一樣強了。
官方文檔的變化
Edit breakpoint
Action name: BreakpointEdit
Condition(6.5及之前版本)
This IDC expression will be evaluated each time the breakpoint is reached. If the expression returns true, the debugger will execute the selected actions. Please note that you can use the register names in the IDC scripts when the debugger is active. Tests like this would be ok, for example: EAX == EBX+5 or Dword(ESP+0x10) == 34
Condition(6.6版本開始)
This IDC expression will be evaluated each time the breakpoint is reached. If the expression returns true (non-zero), the debugger will execute the selected actions. Please note that you can use the register names in the IDC scripts when the debugger is active. Tests like this are allowed, for example: EAX == EBX+5 or Dword(ESP+0x10) == 34
You can also use the "..." button to enter a multiline condition, or specify
another scripting language to use. See here for
more info.
Breakpoint conditions |
![]() |
You can use the "Condition" field of the breakpoint properties to enter an expression which is evaluated when the breakpoint is hit. It can be either an actual condition or just any valid code in IDC or another supported scripting language syntax. By using the "..." button, you can open a multi-line editor for the condtition and switch the scripting language used for evaluating it.
Expressions
If you enter an expression, the result will be used to determine whether the selected actions are exectuted. Some examples of IDC expressions:
Check if EAX is equal to 5:
EAX==5
Check if the first argument to the function is 1:
Dword(ESP)==1
Interpret the second argument to the function as a pointer to Unicode string, print it, and return 0 (so that the execution continues immediately):
Message("Filename: %s\n", GetString(Dword(ESP+4), -1, ASCSTR_UNICODE)), 0
Set EAX to 0 and continue:
EAX=0,0
Statements
You can enter several statements in the multi-line editor. If the last one is a 'return' statement, it is used as the result of the condition. Otherwise the condition is assumed to return 0.
可以看出新變化,支持多行編輯了,更好更方便更加強大。舉得例子也讓我想起逗號表示式了,也就是不斷點打印日志可以使用這種方式。
逗號表達式表達式1,表達式2,表達式3,...... ,表達式n逗號表達式的要領:(1) 逗號表達式的運算過程為:從左往右逐個計算表達式。(2) 逗號表達式作為一個整體,它的值為最后一個表達式(也即表達式n)的值。(3) 逗號 運算符的優先級別在所有運算符中最低。如:(3+5,6+8)的值是14,(a=3*5,a*4)的值是60。
官方網站更新介紹:https://www.hex-rays.com/products/ida/6.6/,里面有許多改變,這里看編輯條件斷點。
Multiline breakpoint conditions
Python users will love this: now it is possible to write a multiline condition right in the 'edit breakpoint' dialog box. IDA even accepts function definitions there!
以前的
1、斷點:
參考:自帶文檔,調試菜單(Debugger submenu)-斷點子菜單(Breakpoints submenu)-編輯斷點(Edit breakpoint)章節和IDC之表達式(IDC: Expressions)一章
條件斷點,可以輸入一個IDC表達式,如果在調試狀態下可以使用寄存器名字。
Condition
This IDC expression will be evaluated each time the breakpoint is reached. If the expression returns true, the debugger will execute the selected actions. Please note that you can use the register names in the IDC scripts when the debugger is active. Tests like this would be ok, for example: EAX == EBX+5 or Dword(ESP+0x10) == 34
案例1:自定義打印跟蹤執行某條語句時的各種值。
Alphabetical list of IDC functions
The following conventions are used in the function descriptions:
'ea' is a linear address 'success' is 0 if a function fails, 1 otherwise 'void' means that function returns no meaningful value (always 0) 'anyvalue' means that function may return value of any type
一個永遠返回假的條件表達式:0 * Message("%s = %d\n", atoa(Dword(R2+0x10)), R2+0x20)
這里我試過,需要與0相乘,確保假。
遠程調試,字符串指針R2+0x10的值是"crack"的表達式
'c' == DbgByte(DbgDword(R2+0x10)) && 'r' == DbgByte(1+DbgDword(R2+0x10)) && 'a' == DbgByte(2+DbgDword(R2+0x10)) && 'c' == DbgByte(3+DbgDword(R2+0x10)) && 'k' == DbgByte(4+DbgDword(R2+0x10))
案例2:根據前一條語句的某些值來對某語句下條件斷點。
CODE:00234EC8 loc_234EC8: ; CODE XREF: sub_234DD8+CB↑j CODE:00234EC8 mov eax, edi CODE:00234ECA call sub_193ED4 CODE:00234ECF push eax ; hWnd CODE:00234ED0 call GetWindowTextLengthW CODE:00234ED5 mov edx, eax CODE:00234ED7 inc edx CODE:00234ED8 mov eax, esi CODE:00234EDA call sub_E48AC CODE:00234EDF mov eax, [esi] CODE:00234EE1 call sub_E4544 CODE:00234EE6 push eax ; nMaxCount CODE:00234EE7 mov eax, [esi] CODE:00234EE9 call sub_E4534 CODE:00234EEE push eax ; lpString 壓入第二參數,緩沖區指針地址,可利用條件斷點保存EAX值 CODE:00234EEF mov eax, edi CODE:00234EF1 call sub_193ED4 CODE:00234EF6 push eax ; hWnd CODE:00234EF7 call GetWindowTextW CODE:00234EFC mov eax, [esi] ; 執行完GetWindowTextW后在這里利用條件斷點查看緩沖區 CODE:00234EFE call sub_E4544 CODE:00234F03 mov edx, eax CODE:00234F05 dec edx CODE:00234F06 mov eax, esi CODE:00234F08 call sub_E48AC
在執行完GetWindowTextW想看里的內容或者根據lpString來下條件斷點。可以這樣:
1、在IDA底部的IDC命令行聲明一個全局變量:extern lpString;
2、在CODE:00234EEE處下表達式始終為假的條件斷點:0 * (lpString = EAX) || 0 * Message("EAX = %x, lpString = %x\n", EAX, lpString)
3、在CODE:00234EFC處下條件斷點,表達式為:0 * Message("GetString(Address_%x)=%s\n", lpString, GetString(Dword(lpString),-1, ASCSTR_UNICODE))
結果打印類似如下:
EAX = 7d71a5c, lpString = 7d71a5c
GetString(Address_7d71a5c)=
EAX = 7d5ebb4, lpString = 7d5ebb4
GetString(Address_7d5ebb4)=
在IDA底部的IDC命令行輸入lpString執行,查看lpString,嗯起作用了
IDC>lpString
131460020. 7D5EBB4h 765365664o 00000111110101011110101110110100b '措'
在CODE:00234EFC處下條件斷點,表達式為:
0 * Message("GetString(%x)=%s\n", lpString, GetString(lpString,-1, ASCSTR_UNICODE))
EAX = 7d71a5c, lpString = 7d71a5c
GetString(7d71a5c)=
EAX = 1377e64, lpString = 1377e64
GetString(1377e64)=Incomplete or Invalid Registration Key
EAX = 7d71a5c, lpString = 7d71a5c
GetString(7d71a5c)=&OK
字符串比較斷點:
斷點地址 User32.dll BOOL SetWindowText(HWND hwnd,LPCTSTR lpString);
斷點條件 0*Message("wchar(%x)=%s\n", Dword(ESP+8), GetString(Dword(ESP+8),-1, ASCSTR_UNICODE)) || GetString(Dword(ESP+8),-1, ASCSTR_UNICODE) == "Incomplete or Invalid Registration Key"
其中,邏輯||前為打印調用的歷史記錄。
2、程式化下條件斷點
見文檔Breakpoint handling functions一章
// Set breakpoint condition // address - any address in the breakpoint range // cnd - breakpoint condition // is_lowcnd- 0:regular condition,1:low level condition // Returns: success success SetBptCndEx(long ea, string cnd, long is_lowcnd); #define SetBptCnd(ea, cnd) SetBptCndEx(ea, cnd, 0)
Debugger: control
*********************************************** Execute one instruction in the current thread. Other threads are kept suspended. // NOTE You must call GetDebuggerEvent() after this call in order to find out what happened. Normally you will get the STEP event but other events are possible (for example, an exception might occur or the process might exit). This remark applies to all execution control functions. The event codes depend on the issued command. returns: successsuccess StepInto(void);
IDA 5.2持調試器除了支持以往的事件的模型,還允許設計一個順序
執行(線性模型)的IDC 腳本來控制調試器。以往的基於事件的模型依然可用,同時也可通過使
用 get_debugger_event()這個函數來支持簡單的線性模型。這個函數暫停插件(或腳本)
的執行直到一個新的調試器時間發生。使用者可以指定他是只對進程掛起事件感興趣或是對
所有事件。也可以進行定時設置,如果沒有其它事件發生,超時后程序可以繼續執行。
#include <idc.idc> //-------------------------------------------------------------------------- static main() { auto code, bptea_some_addrese; AppBpt(bptea_some_addrese); // 在某地址下斷點 StartDebugger("","",""); // 調試start debugger with default params code = GetDebuggerEvent(WFNE_SUSP, -1); // 等待斷點發生... and wait for bpt if ( code <= 0 ) return Failed(code); Message ("Stopped at %a, event code is %x\n", GetEventEA(), GetEventId()); // 打印消息 StepInto(); // 扮演跟進行動 request a single step GetDebuggerEvent(WFNE_SUSP, -1); // ... and wait for app to execute StepInto(); // request a single step GetDebuggerEvent(WFNE_SUSP, -1); // ... and wait for app to execute DelBpt(bptea); } //-------------------------------------------------------------------------- // Print an failure message static Failed(code) { Warning("Failed, sorry (code %d)", code); return 0; }
UUNP 解壓器插件的核心功能
http://blog.csdn.net/eqera/article/details/8239505
#include <idc.idc> //-------------------------------------------------------------------------- static main() { auto ea, bptea, tea1, tea2, code, minea, maxea; auto r_esp, r_eip, caller, funcname; // Calculate the target IP range. It is the first segment. // As soon as the EIP register points to this range, we assume that // the unpacker has finished its work. tea1 = FirstSeg(); tea2 = SegEnd(tea1); // Calculate the current module boundaries. Any calls to GetProcAddress // outside of these boundaries will be ignored. minea = MinEA(); maxea = MaxEA(); // Launch the debugger and run until the entry point if ( !RunTo(BeginEA()) ) return Failed(-1); // Wait for the process to stop at the entry point code = GetDebuggerEvent(WFNE_SUSP, -1); if ( code <= 0 ) return Failed(code); // Set a breakpoint at GetProcAddress bptea = LocByName("kernel32_GetProcAddress"); if ( bptea == BADADDR ) return Warning("Could not locate GetProcAddress"); AddBpt(bptea); while ( 1 ) { // resume the execution and wait until the unpacker calls GetProcAddress code = GetDebuggerEvent(WFNE_SUSP|WFNE_CONT, -1); if ( code <= 0 ) return Failed(code); // check the caller, it must be from our module r_esp = GetRegValue("ESP"); caller = Dword(r_esp); if ( caller < minea || caller >= maxea ) continue; // if the function name passed to GetProcAddress is not in the ignore-list, // then switch to the trace mode funcname = GetString(Dword(r_esp+8), -1, ASCSTR_C); // ignore some api calls because they might be used by the unpacker if ( funcname == "VirtualAlloc" ) continue; if ( funcname == "VirtualFree" ) continue; // A call to GetProcAddress() probably means that the program has been // unpacked in the memory and now is setting up its import table break; } // trace the program in the single step mode until we jump to // the area with the original entry point. DelBpt(bptea); EnableTracing(TRACE_STEP, 1); for ( code = GetDebuggerEvent(WFNE_ANY|WFNE_CONT, -1); // resume code > 0; code = GetDebuggerEvent(WFNE_ANY, -1) ) { r_eip = GetEventEa(); if ( r_eip >= tea1 && r_eip < tea2 ) break; } if ( code <= 0 ) return Failed(code); // as soon as the current ip belongs OEP area, suspend the execution and // inform the user PauseProcess(); code = GetDebuggerEvent(WFNE_SUSP, -1); if ( code <= 0 ) return Failed(code); EnableTracing(TRACE_STEP, 0); // Clean up the disassembly so it looks nicer MakeUnknown(tea1, tea2-tea1, DOUNK_EXPAND|DOUNK_DELNAMES); MakeCode(r_eip); AutoMark2(tea1, tea2, AU_USED); AutoMark2(tea1, tea2, AU_FINAL); TakeMemorySnapshot(1); MakeName(r_eip, "real_start"); Warning("Successfully traced to the completion of the unpacker code\n" "Please rebuild the import table using renimp.idc\n" "before stopping the debugger"); } //-------------------------------------------------------------------------- // Print an failure message static Failed(code) { Warning("Failed to unpack the file, sorry (code %d)", code); return 0; }
二、搜索
addr = FindBinary(0, SEARCH_DOWN, "31 32 33 34 35 36 37 38 39"); #ea = FindText(ea, SEARCH_NEXT | SEARCH_REGEX, 0, 0, "test *[a-zA-Z]*, +[a-zA-Z]*") MinEA() 等價於 GetLongPrm(INF_MIN_EA) 而INF_MIN_EA // int32; The lowest address used // in the program // IDC>auto ea_result = FindText(MinEA() ,SEARCH_DOWN|SEARCH_NEXT, 0, 0, "478467622"); Message("%s %x\n", BADADDR == ea_result ? "bad" : "ok", ea_result); bad ffffffff //查找mov dword ptr [eax+1Ch], offset sub_11010類似這種形式的指令 IDC>auto ea = 0; ea = FindText(ea, SEARCH_DOWN |SEARCH_NEXT | SEARCH_REGEX, 0, 0, "mov +dword ptr \\[[a-zA-Z]+\\+[a-zA-Z0-9_ ]+h\\],[a-zA-Z0-9_ ]*"); Message("Find in %x\n", ea); if(BADADDR != ea) {auto op2_addr = GetOperandValue(ea,1); Message("op2 address is %x\n", op2_addr);} Find in 30801855 //雙擊這里自動定位代碼 op2 address is 24