Ở bài viết trước đã triển khai kĩ thuật tạo shellcode từ mã asm: Kỹ thuật xây dựng Shellcode Windows x86 trên nền MASM – Security Blog. Tuy nhiên, kĩ thuật này có 1 điểm yếu là đối với mã bao gồm nhiều chức năng phức tạp, việc triển khai bằng asm sẽ tốn rất nhiều thời gian và khó khăn hơn.
Bài viết này sẽ hướng dẫn convert shellcode từ mã C/C++.
Kĩ thuật cốt lõi của shellcode để chạy được trên Windows gồm 2 ý chính:
- Resolve Windows API
- Xử lý biến, chuỗi.
Resolve API được xử lý thông qua việc truy cập PEB, có thể xem lại bài viết trước để hiểu rõ. Ở bài viết trước đã tìm hiểu về kĩ thuật delta, sử dụng để truy cập các biến lưu trong sections text.
Tuy nhiên, khi chuyển qua C/C++, kỹ thuật này không còn sử dụng nữa. Các biến bây giờ sẽ được lưu trữ trên stack để có thể truy cập được.
Trước khi bắt đầu, hãy tìm hiểu về cl.exe và ml.exe trong MSVC. Trong Visual Studio, mở Developer Command Prompt để truy cập 2 exe trên. Về cơ bản nó giúp compile từ mã C -> Asm -> Object -> Exe.
cl.exe /c /GS- /FA <file1.c> <file2.c> <file3.c>
ml.exe <file1.asm> <file2.asm> <file3.asm> /link /entry:main
cl.exe sẽ tạo ra các file .asm và .obj. Đối với x86, quá trình này không gây ra lỗi, tuy nhiên đối với x64 sẽ cần phải xử lý file .asm được tạo ra bằng tay trước khi link thông qua ml.exe.
Mã dưới đây mô tả về sự khác biệt trong cách khai báo string.
int main() {
char dataString[] = { 'H', 'e', 'l', 'l', 'o', 'W', 'o', 'u', 'l', 'd'};
char* dataString2 = "HelloWorld";
}
Sử dụng lệnh cl.exe đã mô tả ở trên, file main.asm và main.obj sẽ được tạo ra.

Ở hình trên, string được khai báo thông qua mảng sẽ được lưu trữ trên stack để sử dụng, còn string được khai báo thông qua con trỏ được lưu trữ trong const segment. Điều này làm cho kết quả file PE chứa dữ liệu nằm ngoài sections text.
Ngoài ra trong quá trình tạo ra shellcode x64 có thể phát sinh 1 số segment như pdata hoặc xdata, các segments này có thể xóa đi mà không ảnh hưởng tới kết quả.
Một số lỗi có thể sinh ra trong quá trình compiler asm đòi hỏi phải custom lại file asm, tham khải tại Vx Underground.
2 vấn đề tiếp theo là resolve API và xử lý CRT.
Đối với API, truy cập PEB để lấy các module và address của WinAPI.

Đối với CRT, cần tự viết các hàm sẽ sử dụng trong shellcode.

Như vậy sau khi build ra PE, kết quả sẽ không có bảng reloc, không có bảng IAT, toàn bộ data được lưu trữ trên stack của sections text.
Dump section text sau đó thực hiện inject để test kết quả.