4.2.5.3
Dữ liệu
Nếu
iscode trong cấu trúc xrefblk_t được đặt giá trị 0, thì
tham chiếu thuộc kiểu tham chiếu dữ liệu. Đây là những
giá trị kiểu thành viên có thể khi bạn làm việc với
tham chiếu dữ liệu. Những ghi chú trong kiểu liệt kê
này cũng được lấy từ xref.hpp
// The following
DATA xref types are defined:
enum dref_t
{
dr_U,
// Unknown -- for compatibility with old
// versions. Should not be used anymore.
dr_O,
// Offset
// The reference uses 'offset' of data
// rather than its value
// OR
// The reference appeared because the "OFFSET"
// flag of instruction is set.
// The meaning of this type is IDP dependent.
dr_W,
// Write access
dr_R,
// Read access
dr_T,
// Text (for forced operands only)
// Name of data is used in manual operand
dr_I,
// Informational
// (a derived java class references its base
// class informatonally)
};
|
Ghi
nhớ rằng khi bạn thấy một đoạn như sau trong mã
dissasm, bạn thật sự là đang thấy một tham chiếu dữ
liệu, với 712D9BD9 tham chiếu đến 712C119C:
.idata:712C119C
extrn wsprintfA:dword
.text:712D9BD9 call ds:wsprintfA
|
Trong
trường hợp ở trên, kiểu thành viên của xrefblk_t sẽ
mang giá trị dr_R, bởi ví nó đơn giản là đọc giá trị
tại địa chỉ được mô tả bởi ds:wsprintfA. Một tham
chiếu dữ liệu khác bên dưới, nơi mà chỉ thị push tại
địa chỉ 712EABE2 tham chiếu đến chuỗi ở địa chỉ
712C255C:
.text:712C255C
aversion:
.text:712C255C Unicode
0, <Version>,0
.text:712EABE2 push offset aversion
|
Kiểu
thành viên của xrefblk_t sẽ là dr_o trong trường hợp này,
bởi vì nó truy cập dữ liệu thông qua độ lệch
(offset).
4.3
Những byte cờ
Với
mỗi byte trong tập tin nhị phân, IDA ghi lại tương ứng 4
byte (32-bit) cờ, tất cả được lưu trữ trong tập tin
*.idl. Byte cuối cùng của 4 byte cờ là byte thật sự tại
địa chỉ trong tập tin nhị phân.
Ví
dụ, chỉ thị bên dưới cần một byte (0x55) trong tập
tin đang được đảo mã:
.text:010060FA push
ebp
Cờ
của IDA cho địa chỉ trên trong file được đảo mã là
0x00010755:0001007 là thành phần của cờ và 55 là giá
trị byte ở tại địa chỉ của tập tin. Ghi nhớ rằng
địa chỉ không liên quan đến cờ, vì vậy không thể
dẫn xuất cờ từ địa chỉ hoặc từ chính byte đó –
bạn cần phải sử dụng get_glags_novalue() để lấy giá
trị flag cho một địa chỉ (sẽ nói rõ hơn trong phần
sau)
Hiển
nhiên, không phải tất cả các chỉ thị đều có kích
thước một byte; ví dụ chi thị bên dưới, nó sẽ chiếm
3 byte (0x83 0xEC 0x14). Chỉ thị bên dưới vì vậy sẽ được
trải dài qua 3 địa chỉ 0x010011DE, 0x010011DF and 0x010011E0:
.text:010011DE sub esp,
14h
.text:010011E1
...
Đây
là những cờ tương ứng cho mỗi byte của chỉ thị này:
010011DE: 41010783
010011DF: 001003EC
010011E0: 00100314
|
Bởi
vì ba byte này thuộc về một chỉ thị, byte đầu tiên
của chỉ thị được xem như là đầu, và 2 byte sau được
xem là đuôi. Một lần nữa, hãy chú ý đến byte cuối
cùng của mỗi cờ được đặt tương ứng với những
byte của chỉ thị (0x83, 0xEC, 0x14).
Tất
cả các cờ được định nghĩa trong tập tin bytes.hpp, và
bạn có thể kiểm tra những cờ đó có được bật hay
không bằng việc sử dụng tập cờ được trả về từ
hàm get_flags_novalue(ea_t ea) như là một tham số tương ứng
với hàm kiểm tra cờ. Sau đây là một vài cờ cùng với
những hàm kiểm tra của nó mà sẽ kiểm tra nó có tồn
tại. Một vài hàm được mô tả trong Chương 5 – Hàm và
những thứ khác bạn có thể xem trong tập tin bytes.hpp
Flag Name |
Flag |
Indication |
Wrapper function |
FF_CODE
|
0x00000600L
|
Is the byte code?
|
isCode()
|
FF_DATA
|
0x00000400L
|
Is the byte data?
|
isData()
|
FF TAIL
|
0x00000200L
|
Is this byte a part (non-head) of
an instruction data chunk?
|
isTail()
|
FF UNK
|
0x00000000L
|
Was IDA unable to classify this
byte?
|
isUnknown()
|
FF COMM
|
0x00000800L
|
Is the byte commented?
|
has cmt()
|
FF REF
|
0x00001000L
|
Is the byte referenced elsewhere?
|
hasRef()
|
FF NAME
|
0x00004000L
|
Is the byte named?
|
has name()
|
FF FLOW
|
0x00010000L
|
Does the previous instruction flow
here?
|
isFlow()
|
Trở
về với ví dụ đầu tiên “push ebp” bên trên, nếu
chúng ta tuần tự kiểm tra mỗi cờ được trả về từ
hàm get_flags_novalue(0x010060FA) qua một loạt các cờ ở
trên, chúng ta sẽ có được những kết quả sau:
0x00010755
& 0x00000600 (ff_code) = 0x00000600. Chúng ta thấy đây là
mã.
0x00010755
& 0x00000800 (ff_comm) = 0x00000000. Không phải là ghi chú.
Ví
dụ bên trên chỉ có mục đích mô tả - không nên làm
theo cách ở trên trong plugin của bạn. Như đã được
khuyến cáo, bạn luôn luôn nên sử dụng những hàm trợ
giúp để kiểm tra một giá trị của cờ có được bật
hoặc tắt. Ví dụ tiếp theo sẽ trả về những cờ cho
một loạt các địa chỉ đầu tại vị trí con trỏ của
bạn trong IDA.
#include
<bytes.hpp>
#include
<kernwin.hpp>
msg("%08x\n",
get_flags_novalue(get_screen_ea()));
|
4.4
Trình gỡ rối
Một
trong những chức năng mạnh của IDA là khả năng tương
tác với trình gỡ rối IDA, và nếu bạn không cài đặt
trình plugin gỡ rối nào, nó sẽ trở thành một plugin gỡ
rối với IDA. Một số lớn plugin gỡ rối được mặc
định kèm theo IDA, cùng với những trình khác, và bạn có
thể tìm thấy chúng trong thư mục plugins của IDA.
Tên tập tin
|
Mô tả
|
win32 user.plw
|
Windows local debugger
|
win32 stub.plw
|
Windows remote debugger
|
linux user.plw
|
Linux local debugger (only when running IDA in
Linux)
|
linux stub.plw
|
Linux remote debugger
|
bochs user.plw
|
Bochs local debugger
|
windbg user.plw
|
WinDbg local debugger
|
mac stub.plw
|
Mac remote debugger
|
Chúng
được tự động nạp bởi IDA và sẵn sàng khởi động
qua menu Debugger > Start Process. Kể từ đây, thuật ngữ
“debugger” sẽ thể hiện cho bất cứ công cụ nào bạn
sử dụng ở trên (IDA sẽ chọn một trình gỡ rối phù
hợp nhất cho bạn mặc định)
Như
đã đề cập từ trước, việc viết modun gỡ rối cho
IDA có thể hoàn toàn thực hiện được, nhưng đừng nên
lẫn lộn với việc viết những modun plugin tương tác với
trình gỡ rối. Kiểu plugin thứ 2 sẽ được mô tả bên
dưới.
Bên
cạnh tất cả các hàm được cung cấp để tương tác
với trình gỡ rối, mà sẽ được trình bày trong Chương
5 – Hàm, có một vài cấu trúc dữ liệu và lớp quan
trong mà bạn cần phải hiểu trước khi tìm hiểu sâu
hơn.
4.4.1
Cấu trúc debugger_t
Cấu
trúc debugger_t, được định nghĩa trong tập tin idd.hpp và
được export dạng *dbg, đại diện cho một trình gỡ rối
đang được kích hoạt, và nó sẵn sàng khi trình gỡ rối
được nạp ( ngay lúc khởi động, không phải là lúc bạn
chạy trình gỡ rối).
struct
debugger_t
{
int
version;
//
Expected kernel version,
// should be
IDD_INTERFACE_VERSION
const
char
*name;
// Short debugger
name like win32 or linux
int
id;
//
Debugger API module id
#define
DEBUGGER_ID_X86_IA32_WIN32_USER 0 //
Userland win32 procs (w32 debugging APIs)
#define
DEBUGGER_ID_X86_IA32_LINUX_USER 1 //
Userland linux processes (ptrace())
#define
DEBUGGER_ID_ARM_WINCE_USER 2 //
Windows CE ARM
#define
DEBUGGER_ID_X86_IA32_MACOSX_USER 3 //
Userland MAC OS X processes
#define
DEBUGGER_ID_ARM_EPOC_USER 4 //
Symbian OS
#define
DEBUGGER_ID_ARM_IPHONE_USER 5 //
iPhone 1.x
#define
DEBUGGER_ID_X86_IA32_BOCHS 6 //
BochsDbg.exe 32
#define
DEBUGGER_ID_6811_EMULATOR 7 //
MC6812 emulator (beta)
#define
DEBUGGER_ID_GDB_USER 8 //
GDB remote
#define
DEBUGGER_ID_WINDBG 9 //
WinDBG using Microsoft Debug engine
#define
DEBUGGER_ID_X86_DOSBOX_EMULATOR 10 //
Dosbox MS-DOS emulator
#define
DEBUGGER_ID_ARM_LINUX_USER 11 //
Userland arm linux
register_info_t
*registers; //
Array of registers
int
registers_size;
// Number
of registers
};
|
Như
một modun plugin, bạn hầu như cần phải truy cập đến
một biến được đặt tên, có thể là để kiểm tra
những trình gỡ rối nào mà plugin bạn đang làm việc.
Biến registers và register_size cũng hữu dụng để lấy
danh sách của những thanh ghi sẵn sàng (xem ở phần tiếp
theo), cũng như một vài phương thức khác sẽ được
trình bày trong Chương 5.
4.4.2
Thanh ghi
Nhiệm
vụ chung được đảm nhiệm bởi trình gỡ rối là để
truy cập và thao tác với giá trị các thanh ghi. Trong IDA
SDK, một thanh ghi được mô tả bởi một cấu trúc
register_info_t, và giá trị được chứa trong một thanh ghi
được mô ta bởi cấu trúc regval_t. Bên dưới là một
đoạn vắn tắt về cấu trúc register_info_t, được định
nghĩa trong tập tin idd.hpp.
struct
register_info_t {
const char *name; //
Register full name (EBX, etc)
ulong flags; //
Register special features,
// which can be any
conbination
// of the below.
#define
REGISTER_READONLY 0x0001 // The user can’t modify
// the current value
of this
//register
#define REGISTER_IP
0x0002 // instruction pointer (EIP)
#define REGISTER_SP
0x0004 // stack pointer (ESP)
#define REGISTER_FP
0x0008 // frame pointer (EBP)
#define
REGISTER_ADDRESS 0x0010 // register can contain an address
…
};
|
Thực
thể duy nhất của cấu trúc này có thể truy cập là một
thành viên registers của biến *dbg (một thực thể của
lớp debugger_t), bởi vậy, nó tùy thuộc vào trình gỡ rối
mà bạn làm việc mà danh sách thanh ghi có thể khác nhau
trên hệ thống của bạn.
Để
lấy giá trị của bất cứ thanh ghi nào, hiển nhiên là
trình gỡ rối phải đang chạy. Những chức năng để đọc
và thao tác với giá trị các thanh ghi sẽ được mô tả
chi tiết trong Chương 5 – Hàm, nhưng bây giờ, tất cả
bạn cần biết để lấy giá trị của thanh ghi là sử
dụng biến thành viên ival của lớp regval_t, hoặc sử
dụng fval nếu bạn làm việc với kiểu số thực. Bên
dưới là cấu trúc regval_t, được định nghĩa trong
idd.hpp.
struct regval_t {
ulonglong ival; //
Integer value
ushort fval[6]; //
Floating point value in the internal
// representation
(see ieee.h)
};
|
ival/fval
sẽ phụ thuộc trực tiếp vào những gì được lưu trữ
trong thanh ghi, bởi vậy nếu EBX chứa 0X, ival (một khi
được lấy giá trị thông qua get_reg_val()), cũng sẽ chứa
0xD
Ví
dụ sau đây sẽ lặp qua tất cả các thanh ghi, và hiển
thị giá trị của mỗi thanh ghi. Nếu bạn chạy nó ngoài
chế độ dò lỗi, giá trị mỗi thanh ghi sẽ là 0xFFFFFFF:
#include <dbg.hpp>
// Loop through all
registers
for (int i = 0; i <
dbg->registers size; i++) { regval_t val;
// Get the value
stored in the register
get reg
val((dbg->registers+i)->name, &val);
msg("%s:
%08a\n", (dbg->registers+i)->name, val.ival);
}
|
Sau
khi đặt một điểm dừng và chạy chương trình thực thi
của tôi trong trình dò lỗi, tôi gọi plugin và thấy kết
quả được hiển thị như bên dưới:
EAX
|
00000001
|
EBX
|
00000000
|
ECX
|
00000022
|
EDX
|
00000004
|
ESI
|
00251E50
|
EDI
|
0093A21C
|
EBP
|
0006F9FC
|
No comments:
Post a Comment