Friday, May 31, 2019

So sánh các ngôn ngữ trung gian IR!

Why did you choose VEX instead of another IR (such as LLVM, REIL, BAP, etc)?

We had two design goals in angr that influenced this choice:
  1. angr needed to be able to analyze binaries from multiple architectures. This mandated the use of an IR to preserve our sanity, and required the IR to support many architectures.
  2. We wanted to implement a binary analysis engine, not a binary lifter. Many projects start and end with the implementation of a lifter, which is a time consuming process. We needed to take something that existed and already supported the lifting of multiple architectures.
Searching around the internet, the major choices were:
  • LLVM is an obvious first candidate, but lifting binary code to LLVM cleanly is a pain. The two solutions are either lifting to LLVM through QEMU, which is hackish (and the only implementation of it seems very tightly integrated into S2E), or McSema, which only supported x86 at the time but has since gone through a rewrite and gotten support for x86-64 and aarch64.
  • TCG is QEMU's IR, but extracting it seems very daunting as well and documentation is very scarse.
  • REIL seems promising, but there is no standard reference implementation that supports all the architectures that we wanted. It seems like a nice academic work, but to use it, we would have to implement our own lifters, which we wanted to avoid.
  • BAP was another possibility. When we started work on angr, BAP only supported lifting x86 code, and up-do-date versions of BAP were only available to academic collaborators of the BAP authors. These were two deal-breakers. BAP has since become open, but it still only supports x86_64, x86, and ARM.
  • VEX was the only choice that offered an open library and support for many architectures. As a bonus, it is very well documented and designed specifically for program analysis, making it very easy to use in angr.
While angr uses VEX now, there's no fundamental reason that multiple IRs cannot be used. There are two parts of angr, outside of the angr.engines.vexpackage, that are VEX-specific:
  • the jump labels (i.e., the Ijk_Retfor returns, Ijk_Callfor calls, and so forth) are VEX enums.
  • VEX treats registers as a memory space, and so does angr. While we provide accesses to state.regs.raxand friends, on the backend, this does state.registers.load(8, 8), where the first 8is a VEX-defined offset for raxto the register file.
To support multiple IRs, we'll either want to abstract these things or translate their labels to VEX analogues.

Tìm hiểu file ELF

Cấu trúc file ELF
Chương trình thực thì trên hệ điều hành Linux nhúng chủ yếu là các file ELF (Executable and Linking Format). Mỗi file ELF gồm có phần header, các bảng chứa thông tin quản trị và các đoạn chưa dữ liệu và code của chương trình. 3 phần hcinhs của thông tin quản trị của file ELF là ELF header, section table và program table. ELF header trở đến section và program table, section table giữ thông tin về các section của file ELF trên đĩa và program table chứa thông tin về cách copy các section từ ổ đĩa vào bộ nhớ khi thực thi.
Đa số các file ELF chứa đầy đủ 3 phần như hình bên, song chỉ có phần header là bắt buộc. Trong file excutable ELF, trường program table là bắt buộc, trong các file linkable thì trường section table là bắt buộc






Saturday, May 25, 2019

Tìm hiểu pyvex

Đang ý tưởng tìm hiểu cách phát hiện mã độc đa nền tảng, tức học các mẫu mã độc trên x86 mà có thể phát hiện mã độc trên mips, arm...
Một trong các hương đó là chuyển về mã trung gian chung
Một trong các phương pháp tốt dựa trên Valgrind và angr là Vex Il trên cơ sở PyVex https://github.com/angr/pyvex

Để giải quyết vấn đề đa kiến trúc, ngôn ngữ trung gian là cần thiết. Những điều khác biệt ở các kiến trúc chip khác nhau là:
1. Register names: tên và số lượng các thanh ghi của các kiến trúc chip khác nhau là khác nhau rất nhiều, tất nhiên có những nhóm phổ biến như thanh ghi chung, thành ghi stack, thanh ghi cờ điều kiện...
2. Memory access: có nhiều chế độ truy cập khách nhau như big/little-endian.
3. Memory segmentation
4. Instruction side-effects: nhiều lệnh có ảnh hưởng ngầm đến các lệnh khác.

Để giải quyết bài toán khác biệt này, IR hướng tới giải pháp trừu tượng hoá và tường minh hoá các hành động và trạng thái để có thể giải quyết đa số các trường hợp.

Các thành phần cơ bản của Vex:
  • Expressions. IR Expressions represent a calculated or constant value. This includes memory loads, register reads, and results of arithmetic operations.
  • Operations. IR Operations describe a modification of IR Expressions. This includes integer arithmetic, floating-point arithmetic, bit operations, and so forth. An IR Operation applied to IR Expressions yields an IR Expression as a result.
  • Temporary variables. VEX uses temporary variables as internal registers: IR Expressions are stored in temporary variables between use. The content of a temporary variable can be retrieved using an IR Expression. These temporaries are numbered, starting at t0. These temporaries are strongly typed (i.e., "64-bit integer" or "32-bit float").
  • Statements. IR Statements model changes in the state of the target machine, such as the effect of memory stores and register writes. IR Statements use IR Expressions for values they may need. For example, a memory store IR Statement uses an IR Expression for the target address of the write, and another IR Expression for the content.
  • Blocks. An IR Block is a collection of IR Statements, representing an extended basic block (termed "IR Super Block" or "IRSB") in the target architecture. A block can have several exits. For conditional exits from the middle of a basic block, a special Exit IR Statement is used. An IR Expression is used to represent the target of the unconditional exit at the end of the block.
t0 = GET:I32(16)           1
t1 = 0x8:I32                  2
t3 = Sub32(t0,t1)          3
PUT(16) = t3                 4
PUT(68) = 0x59FC8:I32        5

Vex có mấy loại biểu thức phổ biến:
1. hằng số như lệnh 2, đặt tên là "con"
2. đọc lấy giá trị lưu trong thanh ghi như lệnh 1, đặt tên là "get"

3. đặt giá trị cho thanh ghi, đặt tên là "put"
4. đọc giá trị từ thanh ghi tạm, ví dụ RdTmp(t10), đặt tên là "RdT"
5. ghi giá trị vào thanh ghi tạm, ví dụ t2= 0x12, đặt tên là "WdT"
6. đọc giá trị từ bộ nhớ, đặt tên là "LDle"
7. ghi gía trị vào bộ nhớ, đặt tên "STle"
8. lệnh điều kiện if, đặt tên là ite
9. các toán tử như lệnh 3, đặt tên theo toán tử, 
đang tìm danh sách các toán tử mà vex hỗ trợ

Trong 1 câu lệnh của vex có thể có thể gồm nhiều biểu thức, toán tử và toán hang. Việc trích chọn đặc trưng n-gram sẽ chọn 1 câu là 1 biểu thức đặc trưng có thứ tự ưu tiên, như vậy có 1 số biểu thức sẽ không xuất hiêện là "gram", ví dụ như: con, vì hằng số bao giờ cũng sẽ gắn vào thanh ghi nào đó nên lấy "gram" là gán thanh ghi. 











Phát hiện bug trong phần mềm và tự động sửa!

Một chủ đề khá hay mà tôi mới được tiếp cận là làm sao tự động phát hiện lỗi và sửa lỗi phần mềm, chương trình tôi đang quan tâm là các file ELF trên Embedded Linux. Vì đang nghiên cứu IoT nên tôi chọn các giải pháp đa kiến trúc chip!
Trước tiên tôi gặp công cụ tự sửa lỗi trong firmware https://github.com/eschulte/netgear-repair

Công cụ thứ 2 giúp check phát hiện lỗi trong file ELF là https://github.com/fkie-cad/cwe_checker

Quá tìm tìm hiểu hướng này còn phát hiện ra công cụ rất hay https://fkie-cad.github.io/FACT_core/
Tôi sẽ tìm hiểu và giới thiệu các công cụ này trong bài này