Trao đổi với tôi

http://www.buidao.com

11/5/09

[Programming] Undocumented COFF Object Files

Undocumented COFF Object Files

Đa số các compiler dịch mã nguồn của chương trình thành file object. File object là một định dạng file trung gian, nó chứa các chỉ thị máy và các dữ liệu nhị phân lúc thực thi (biến toàn cục, các chỉ thị của linker) cùng với một số thông tin mở rộng nào đó như thông tin debug (debug information). Những thông tin này cho phép trình linker/loader kết hợp các module object để tạo thành một file thực thi .EXE (.DLL hoặc .SYS) duy nhất. Điều này cho phép các lập trình viên liên kết các thư viện nhị phân và module object khác nhau được viết và biên dịch từ những module chương trình chính khác nhau.

clip_image004

Mỗi thành phần của file COFF object là một section và có kèm theo thông tin debug của symbol (biến, hàm). Các section của COFF:

  • COFF File Header (File Header, COFF Header)
  • Optinal Information (Optinal Header)
  • Bảng header của các section (Section Header)
  • Nội dung của các section (Section Content hoặc là Raw Data của mỗi section)
  • Relocation information của mỗi section
  • Line Number của mỗi section (có thể không có)
  • Symbol table
  • String table

COFF HEADER

Optional Information

Section 1 Header

...

Section n Header

Raw Data for Section 1

...

Raw Data for Section n

Relocation Info for Sect. 1

...

Relocation Info for Sect. n

Line Numbers for Sect. 1

...

Line Numbers for Sect. n

SYMBOL TABLE

STRING TABLE

Như đã nói ở trên, sau khi tạo các file object bạn phải sử dụng một công cụ có tên là linker để liên kết các module lại với nhau thành một file thực thi duy nhất. Trong bài viết này, chúng ta sẽ tìm hiểu chi tiết các thành phần của các file COFF Object này.

Ở đây để cho dễ hình dung, tôi có vẽ một lược đồ UML tóm tắt các thành phần cơ bản mà COFF Object file (có thể) có.

clip_image002[4]

Lược đồ này cho thấy mỗi COFF Object file đều có một Symbol table, và có ít nhất là 1 section. Section relocation có thể có hoặc không.

Để trình bày một cách chi tiết cho bạn hiểu, tôi sẽ code một chương trình C đơn giản như sau:

   1: #include 
   2: #include 
   3:  
   4: int main (void)
   5: {
   6:     LPVOID lp= HeapAlloc(GetProcessHeap(),0,10);
   7:     printf ("Hello World! %p\n",lp);
   8: }

Để tạo ra COFF Object file, đầu tiên bạn phải biên dịch nó. Để biên dịch bạn sử dụng cl.exe với option /c (chỉ tạo ra file object không gọi trình linker một cách tự động) như sau cl /c test.c

clip_image002[6]

Sau khi đã biên dịch nó bạn có thể sử dụng công cụ dumpbin.exe hoặc dumpbinGUI.exe để kiểm tra các thông tin chi tiết của file object. Rất đơn giản, chỉ cần gõ lệnh dumpbin /all tên_file.obj

Căn cứ vào kết quả sau khi thực hiện quá trình dump và lược đồ UML trên ta thấy file COFF Object có một số section và một trong số đó là section . drectve. Section này chứa các tham số dòng lệnh mà trình linker sẽ đọc và sử dụng nó trong suốt quá trình thực hiện liên kết các file object với nhau. Các tham số này được biên dịch như chúng đã được định nghĩa. Bạn có thể thấy rằng mặc định thì quá trình biên dịch sẽ chèn 2 tham số: /DEFAULTLIB:”LIBCMT” /DEFAULTLIB: “OLDNAMES”. Các tham số này quy định các thư viện C lúc thực thi được trình linker sử dụng. LIBCMT là thư viện cho biết chúng ta build static multi-thread của CRT (C Run-time) ở dạng nào (Debug hay là Release). OLDNAME chính là thư viện cung cấp tên hàm đã được biên dịch (ví dụ như là _malloc).

clip_image004[6]

Nếu bạn compile file mã nguồn có option /ZI thì kết quả dump sẽ có thêm section .debug$S. Section này chứa những thông tin debug mà chúng ta có thể sử dụng nó về sau để debug những lỗi trong mã nguồn (nếu có).

clip_image006[4]

Section .data chứa các biến toàn cục và chuỗi được sử dụng. Như bạn thấy trong hình bên dưới có chuỗi Hello World! %p\n. Tại sao? Bởi vì trình biên dịch khi thấy chuỗi này được khai báo, nó sẽ đặt chuỗi này vào trong section .data. Bạn cũng sẽ thấy các biến toàn cục (biến được khai báo bên ngoài 1 hàm). Trong trường hợp ví dụ của chúng ta không có biến toàn cục.

clip_image008

Section .text là nơi chứa mã lệnh. Tại section RAW DATA #4 trong hình bên dưới bạn có thể thấy nhiều mã hexa như 55 8B EC 51 6A. Những con số này chính là mã opcodes mà vi xử lý tạo ra. Mỗi lệnh assembly (MOV, ADD, CALL, etc) chúng đều có mã opcode được quy định sẵn trong cấu trúc IA032 của Intel.

clip_image010

Link: http://nhatphuongle.spaces.live.com/blog/cns!320FF19317F0C9A2!665.entry