相比於直接fuzzing大型程序本身,針對程序的某一特定功能寫wrapper后再fuzzing則要高效的多。網上搜了下,僅有兩篇關於foxit reader的wrapper文章,一個用python,另外一個用C++,而且針對的foxit reader版本也比較舊。本篇的目的通過分析C++的wrapper原理,來寫出最新版foxit reader(Version: 9.1.0.5096)的ConvertToPDF功能的wrapper。
首先看下ConvertToPDF_x86.dll插件的反匯編部分
剛開始分配0x2760h大小的內存,然后可以看到
.text:10015BC7 mov ecx, eax
.text:10015BC9 call sub_100150C0
從這兩句可以猜測ConvertToPDF_x86.dll插件中存在虛函數,因為ecx中存儲有類實例的this指針,它作為隱藏的第一個參數傳遞給sub_100150C0。具體原理可參考http://www.openrce.org/articles/full_view/23。然后繼續跟進sub_100150C0函數,如下
根據這段代碼可以確定esi中存儲有虛函數表的首地址,虛函數表的具體函數如下:
ConvertToPDF_x86.dll插件的主要構成函數如上圖,我們只需函數之間的確定執行流程、每個函數的主要參數內容及個數即可完成wrapper。
主要的函數流程依次為
ConvertToPDF_x86!CreateFXURLToHtml+0x450
ConvertToPDF_x86!CreateFXURLToHtml+0xc90
ConvertToPDF_x86!CreateFXPDFConvertor+0x90
參數個數的確定,因為函數的調用約定遵循thiscall,所以每次調用完函數后,由被調用函數自動清除函數參數,具體代碼為ret xx
64dd020c 0000000a 0:000:x86> bp ConvertToPDF_x86!CreateFXURLToHtml+0x450 0:000:x86> g Breakpoint 1 hit ConvertToPDF_x86!CreateFXURLToHtml+0x450: 64a73f10 55 push ebp 0:000:x86> uf ConvertToPDF_x86!CreateFXURLToHtml+0x450 ConvertToPDF_x86!CreateFXURLToHtml+0x450: 64a73f10 55 push ebp 64a73f11 8bec mov ebp,esp 64a73f13 6aff push 0FFFFFFFFh 64a73f15 68a804dc64 push offset ConvertToPDF_x86!ConnectedPDF::ConnectedPDFSDK::FCP_SendEmailNotification+0x2cc28 (64dc04a8) 64a73f1a 64a100000000 mov eax,dword ptr fs:[00000000h] 64a73f20 50 push eax 64a73f21 83ec14 sub esp,14h 64a73f24 53 push ebx
。。。。。。。。。。。。。。。。。。
ConvertToPDF_x86!CreateFXURLToHtml+0xb70: 64a74630 33c0 xor eax,eax 64a74632 8b4df4 mov ecx,dword ptr [ebp-0Ch] 64a74635 64890d00000000 mov dword ptr fs:[0],ecx 64a7463c 59 pop ecx 64a7463d 5f pop edi 64a7463e 5e pop esi 64a7463f 5b pop ebx 64a74640 8be5 mov esp,ebp 64a74642 5d pop ebp 64a74643 c20400 ret 4 //參數個數為1
參數內容為0x2
據此可以確定另外兩個函數的參數個數和內容。
網上參考的的wrapper的具體代碼內容如下
/* foxit-fuzz.cpp - simple console wrapper for ConvertToPDF_x86.dll @richinseattle / rjohnson@moflow.org NOTES: Must install the foxit pdf printer globally Harness targets foxit 9.0 API by default Can target 7.3.4 if FOXIT_734 is defined and ConvertToPDF_x86.734.dll is in path afl-fuzz.exe -i %INPUT_DIR% -o foxit_out -D %DynamoRIO_ROOT%\bin32 -t 20000 -- -coverage_module ConvertToPDF.dll -target_module foxit-fuzz.exe -target_method convert_to_pdf -nargs 2 -fuzz_iterations 5000 -- %CD%\foxit-fuzz.exe @@ NUL */ #include <Windows.h> #include <String.h> #include <iostream> using namespace std; typedef void * (__stdcall *CreateFXPDFConvertor_t)(); typedef int(__thiscall *InitLocale_t)(void *_this, int, wchar_t * lc_str); typedef int(__thiscall *InitPrinter_t)(void* _this, wchar_t *printer_name); typedef int(__thiscall *InitPdfConverter_t)(void* _this, int mode); #ifdef FOXIT_734 typedef int(__thiscall *ConvertToPdf_t)(void* _this, wchar_t *convert_buf, int p2, int p3); #else typedef int(__thiscall *ConvertToPdf_t)(void* _this, wchar_t *convert_buf, int p2, int p3, int p4, int p5, int p6, int p7, int p8); #endif typedef struct ConverterFuncTable_t { ConvertToPdf_t ConvertToPdf; InitPdfConverter_t InitPdfConverter; InitPrinter_t InitPrinter; //InitLocale_t InitLocale; } ConverterFuncTable; typedef struct ConverterClass_t { ConverterFuncTable_t *vfp_table; } ConverterClass; #ifdef FOXIT_734 char *target_library = "ConvertToPDF_x86.734.dll"; #else char *target_library = "ConvertToPDF_x86.dll"; #endif char *target_function = "CreateFXPDFConvertor"; wchar_t * printer_name = L"Foxit Reader PDF Printer"; ConverterClass *pdfconverter = NULL; int init_target_library() { int retVal = 0; CreateFXPDFConvertor_t CreateFXPDFConvertor = (CreateFXPDFConvertor_t)GetProcAddress(LoadLibraryA(target_library), target_function); // create an instance of CreateFXPDFConvertor pdfconverter = (ConverterClass *)CreateFXPDFConvertor(); ConverterFuncTable *vfp_table = pdfconverter->vfp_table; cout << "Function table: " << endl; cout << "CreateFXPDFConvertor: " << hex << CreateFXPDFConvertor << endl; cout << "InitPdfConverter: " << hex << vfp_table->InitPdfConverter << " CreateFXPDFConvertor+0x" << hex << (unsigned long)vfp_table->InitPdfConverter - (unsigned long)CreateFXPDFConvertor << endl; cout << "InitPrinter: " << hex << vfp_table->InitPrinter << " CreateFXPDFConvertor+0x" << hex << (unsigned long)vfp_table->InitPrinter - (unsigned long)CreateFXPDFConvertor << endl; cout << "ConvertToPdf: " << hex << vfp_table->ConvertToPdf << " CreateFXPDFConvertor+0x" << hex << (unsigned long)vfp_table->ConvertToPdf - (unsigned long)CreateFXPDFConvertor << endl << endl; // init converter retVal = vfp_table->InitPdfConverter(pdfconverter, 2); if (retVal) cout << "Error: InitPdfConverter(): " << retVal << endl; // init printer device retVal = vfp_table->InitPrinter(pdfconverter, printer_name); if (retVal) cout << "Error: InitPrinter(): " << retVal << endl; return retVal; } extern "C" __declspec(dllexport) int wmain(int argc, wchar_t *argv[]); extern "C" __declspec(dllexport) int convert_to_pdf(ConvertToPdf_t convert, wchar_t * converter_buf); int convert_to_pdf(ConvertToPdf_t convert, wchar_t * converter_buf) { #ifdef FOXIT_734 return convert(pdfconverter, converter_buf, 0, 0); #else return convert(pdfconverter, converter_buf, 0, 0, 0, 0, 0, 0, 0); #endif } int wmain(int argc, wchar_t *argv[]) { int retVal = 0; int converter_buf_count = 0; int converter_buf_size = 0; wchar_t *converter_buf = NULL; wchar_t *input_path = NULL; wchar_t *output_path = L"nul"; #ifdef FOXIT_734 cout << "foxit-fuzz (target v7.3.4) - rjohnson@moflow.org" << endl << endl; #else cout << "foxit-fuzz (target v9.0) - rjohnson@moflow.org" << endl << endl; #endif if (argc < 2) { wcout << "usage: " << argv[0] << " <input> [output]" << endl; return -1; } if (GetFileAttributesW(argv[1]) == -1) { cout << "error: input file path" << endl; return -1; } input_path = argv[1]; if (argc == 3) output_path = argv[2]; // setup buffer for converting PDF converter_buf_count = 0x1000; converter_buf_size = converter_buf_count * sizeof(wchar_t); converter_buf = (wchar_t *)calloc(converter_buf_count, sizeof(wchar_t)); wcsncpy_s(converter_buf, converter_buf_count, input_path, wcslen(input_path)); wcsncpy_s(converter_buf + (0x208 / sizeof(wchar_t)), converter_buf_count - (0x208 / sizeof(wchar_t)), output_path, wcslen(output_path)); // create pdfconverter class and initialize library if (init_target_library()) { cout << "Error intializing target library" << endl; return -1; } // execute wrapper for fuzzing retVal = convert_to_pdf(pdfconverter->vfp_table->ConvertToPdf, converter_buf); free(converter_buf); if (retVal) { cout << "Error: ConvertToPdf(): " << retVal << endl; return -1; } return 0; }
重點說明的代碼為
wcsncpy_s(converter_buf + (0x208 / sizeof(wchar_t)), converter_buf_count - (0x208 / sizeof(wchar_t)), output_path, wcslen(output_path));
其中0x208表示input_path與output_path的間隔距離。
其實不用更改上述的任何代碼,直接編譯即可使用
用winafl時注意命令行要改為
afl-fuzz.exe -i %INPUT_DIR% -o foxit_out -D %DynamoRIO_ROOT%\bin32 -t 20000 -- -coverage_module ConvertToPDF.dll -coverage_module foxit-fuzz.exe -target_module foxit-fuzz.exe -target_method convert_to_pdf -nargs 2 -fuzz_iterations 5000 -- %CD%\foxit-fuzz.exe @@ NUL
否則報錯,運行結果如下圖所示:
跑了三天,一個crash都沒有,,,,,,,估計已經被很多人跑了,fuzz好難