Phần 1:
http://vcyberwarface.blogspot.com/2014/02/xay-dung-trinh-cam-cho-ida-pro-phan-1.html
Phần 2:
http://vcyberwarface.blogspot.com/2014/02/xay-dung-trinh-cam-cho-ida-pro-phan-2.html
Phần 3:
http://vcyberwarface.blogspot.com/2014/02/xay-dung-trinh-cam-cho-ida-pro-phan-3.html
4. Cơ bản
Có nhiều lớp, cấu trúc dữ liệu và
kiểu khác nhau trong IDA SDK, một số được sử dụng nhiều hơn những thứ khác. Mục
tiêu của phần này là sẽ giới thiệu bạn với những phần đó, vì chúng cung cấp một
cái nhìn sâu hơn vào những gì mà IDA biết về tập tin disassemle, và có thể đưa
ra những ý tưởng về những khả năng mà bạn có thể sử dụng với SDK.
Một vài lớp và cấu trúc có kích
thước quá lớn, với nhiều biến thành viên và phương thức/hàm. Trong phần này, hầu
hết các biến sẽ được mô tả, những phương thức sẽ được mô tả trong Chương 5 –
Hàm. Một vài đoạn chú thích mã ở bên dưới được lấy trực tiếp từ IDA SDK, một
vài là do tôi chú thích, và một số khác thì kết hợp cả hai. Những chỉ thị tiền
xử lý #define, trong một vài trường hợp, được sử dụng bên cạnh nhiều biến thành
viên, giống như cách mà nó được dùng trong SDK. Tôi đặt những phần đó ở đây, bởi
vì nó mô tả một cách rõ ràng những giá trị hợp lệ mà những biến thành viên có
thể có.
Chú ý quan trọng về mã ví dụ: Mã từ bất kỳ phần ví dụ nào của phần
này nên được đặt trong hàm iDAP_run() ở khuôn mẫu 3.5, trừ khi nó có mục đích
khác.
4.1 Những kiểu dữ liệu cơ sở
Những kiểu sau được sử dụng qua
suốt SDK trong tài liệu này, bởi vậy, điều quan trọng là bạn phải nhận ra được
nó khi nó được sử dụng.
Tất cả những kiểu bên dưới đều
thuộc kiểu nguyên dài không dấu (unsigned long), và kiểu nguyên dài trong hệ thống
64bit. Chúng được định nghĩa trong pro.h.
Kiểu
|
Mô tả
|
ea_t
|
Viết tắt của ‘Effective Address’, và mô tả hầu như tất cả
địa chỉ nào trong IDA (bộ nhớ, tập tin, limits, vvv)
|
sel_t
|
Chọn lọc phân đoạn, như trong mã, ngăn xếp và đoạn dữ liệu.
|
uval_t
|
Dùng để đại diện cho một giá trị không dấu.
|
asize_t
|
Hầu hết được dùng để đại diện cho kích cỡ một thứ gì đó,
thường là một đoạn của bộ nhớ.
|
Những kiểu dữ liệu tiếp theo là
những kiểu nguyên có dấu, và kiểu nguyên dài có dấu trong nền tảng 64bit. Chúng
được định nghĩa trong tập tin pro.h
Kiểu
|
Mô tả
|
sval_t
|
Dùng để đại diện cho giá trị có dấu
|
adiff_t
|
Dùng để đại diện cho sự khác biệt giữa hai địa chỉ.
|
Cuối cùng, có một số hằng số cần
phải được chú ý; một trong số đó là BADADDR, nó đại diện cho một địa chỉ không
hợp lệ hoặc không tồn tại, bạn sẽ thấy nó được sử dụng trong vòng lặp để dò tìm
phần kết của một khoảng địa chỉ đọc được hoặc một cấu trúc. Bạn cũng sẽ bắt gặp
MAXSTR được sử dụng trong định nghĩa bộ đệm ký tự, có giá trị 1024.
4.2 Những cấu trúc và lớp cơ sở
4.2.1 Siêu thông tin
struct idainfo
{
char tag[3]; // 'IDA'
ushort version; // Version of database
char procName[8]; // Name of current processor
void set_proc_name(const char
*name)
{
size_t len = strlen(name) + 1;
memcpy(procName, name, qmin(len, sizeof(procName)));
}
char *get_proc_name(char
*buf) const
{
buf[0] = procName[0];
buf[1] = procName[1];
buf[2] = procName[2];
buf[3] = procName[3];
buf[4] = procName[4];
buf[5] = procName[5];
buf[6] = procName[6];
buf[7] = procName[7];
buf[8] = '\0';
return buf;
}
uchar lflags; // Misc. flags
…………
};
|
Cấu trúc idainfo, được lưu trữ vật
lý trong tập tin cơ sở dữ liệu của IDA (IDB), lưu giữ những gì mà tôi sẽ xem
như là những ‘siêu thông tin’ về việc khởi tạo cho tập tin được nạp vào IDA. Nó
không thay đổi nếu nhiều tập tin được nạp. Đây là một vài phần hấp dẫn của nó,
như được định nghĩa trong ida.hpp:
inf là một thực thể có thể truy cập
toàn cục của cấu trúc này. Bạn sẽ thường thấy những kiểm tra đối với
inf.procName trong hàm khởi tạo của plugins, kiểm tra kiến trúc máy mà plugins
được viết để làm việc.
Ví dụ, nếu bạn viết một plugins
chỉ làm việc với loại tập tin nhị phân dạng PE và ELF cho kiến trúc x86, bạn có
thể thêm vào những dòng sau vào phần khởi tạo của plugin (iDAP_init từ khuôn mẫu
plugin của chúng ta ở mục 3.5).
// “metapc” đại diện cho kiến trúc x86
if (strncmp(inf.procName,
"metapc", 8) != 0
||
inf.filetype != f_ELF && inf.filetype != f_PE))
{
error("Only
PE and ELF binary type compiled"
"for the x86 platform is supported,
sorry.");
return
PLUGIN SKIP;
//
Trả về PLUGIN_SKIP có nghĩa rằng plugin này
//
sẽ không được nạp
}
return PLUGIN KEEP; // Cho phép plugin tiếp tục nạp
|
F_ELF và f_PE là hai phần tử
trong kiểu liệt kê filetype_t được định nghĩa trong tập tin tiêu đề ida.hpp.
4.2.2 Vùng
Trước khi đi vào chi tiết trong
những cấu trúc lớp ở mức cao hơn để làm việc với đoạn, hàm và các chỉ thị,
chúng ta hãy xem xét hai khái niệm nòng cốt; tên vùng và khối điều khiển vùng.
4.2.2.1 Cấu trúc area_t
Một vùng được đại diện bằng một cấu
trúc area_t, được định nghĩa trong tập tin tiêu đề area.hpp. Dựa vào những ghi
chú trong tập tin này, ta có thể nói một cách cụ thể:
“Vùng” bao gồm nhiều vùng con thuộc kiểu area_t. Một vùng là một khoảng không rỗng bao
gồm những địa chỉ tuyến tính (được xác định bởi địa chỉ bắt đầu và địa chỉ kết
thúc, địa chỉ kết thúc không được chỉ rõ trong vùng) với những thuộc tính của
nó.Ví dụ, một đoạn là một tập của các vùng.
Bạn có thể thấy phần khai báo bên
dưới được lấy từ định nghĩa area_t, một vùng được định nghĩa bởi địa chỉ bắt đầu
(startEA) và địa chỉ kết thúc (endEA) – địa chỉ này thường bị bỏ qua. Cùng một
loạt các phương thức để kiểm tra nếu một vùng có chứa một địa chỉ cụ thể hay
không, kiểm tra vùng rỗng, và cho biết kích thước của vùng. Một đoạn là một
vùng, nhưng một hàm cũng là một vùng, điều
đó có nghĩa là nhiều vùng có thể lồng nhau.
struct area_t
{
............
ea_t
startEA;
ea_t
endEA; // endEA bị
bỏ qua
area_t(void)
{}
area_t(ea_t ea1, ea_t ea2) : startEA(ea1), endEA(ea2) {}
............
};
|
Theo cách nói kỹ thuật, nói rằng
hàm và phân đoạn là vùng, là nói rằng lớp func_t và segment_t được mở rộng từ lớp
area_t. Điều này có nghĩa rằng tất cả các biến và hàm trong cấu trúc area_t đều
có thể được sử dụng bởi func_t và segment_t (ví dụ, segment_t.startEA và
func_t.contains() đều hợp lệ). func_t và segment_t thêm vào area_t với những biến
và hàm riêng biệt của chúng. Chúng sẽ được trình bày sau.
Một vài lớp được mở rộng từ lớp
area_t như ở bên dưới:
Kiểu (tập tin)
|
Mô tả
|
hidden_area_t (bytes.hpp)
|
Vùng ẩn là nơi mà mã/dữ liệu được thay thế và tóm gọn bởi mô tả có thể
được mở rộng để xem những thông tin ẩn.
|
regvar_t (frame.hpp)
|
Những tên thanh ghi được thay thế bởi những tên định nghĩa bởi người
dùng (biến thanh ghi)
|
memory_info_t (idd.hpp)
|
Một khối bộ nhớ (khi sử dụng trình dò lỗi)
|
segreg_t (srarea.hpp)
|
Thông tin về thanh ghi đoạn (CS, SS, vv, trên nền x86)
|
4.2.2.2 Lớp areacb_t
Một khối điều khiển vùng (Area
Control Block) được đại diện bằng lớp
areacb_t, và được định nghĩa trong tập tin area.h. Chú thích cho nó, như được
trình bày bên dưới, có rất ít thông tin, nhưng không thật sự cần thiết:
“areacb_t” là một lớp cơ sở được
sử dụng trong nhiều phần của IDA
Để mở rộng định nghĩa này; lớp
này chỉ đơn giản là một tập hợp các phương thức được sử dụng để thao tác với vùng.
Những phương thức này bao gồm get_area_qty(), get_next_area() và một số khác. Hầu
như bạn sẽ không sử dụng những phương thức này một cách trực tiếp, khi bạn làm
việc với những ví dụ, bạn sẽ sử dụng nhiều các phương thức của các lớp dẫn xuất
như func_t và segment_t, và đây nguyên tắc chung được áp dụng cho những lớp được
mở rộng từ area_t.
Có hai thực thể toàn cục của lớp
areacb_t, tên là segs (được định nghĩa trong segment.hpp) và funcs (được định
nghĩa trong funcs.hpp), mà nó đại diện cho tất cả các phân đoạn và hàm, tương ứng
với tập tin bị đảo mã hiện tại. Bạn có thể thực thi đoạn mã sau để liệt kê số
lượng phân đoạn và hàm trong tập tin đang bị đảo mã được mở bởi IDA (nhớ rằng đầy
không phải là đoạn mã độc lập, nó phải được đặt trong iDAP_run):
#include <segment.hpp>
#include <funcs.hpp>
msg("Segments: %d, Functions: %d\n",
segs.get_area_qty(),
funcs.get_area_qty());
|
(Còn tiếp)