st404

My Links

Blog Stats

试写foxit reader的ConvertToPDF功能的wrapper

  相比于直接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好难

posted on 2018-08-03 09:57  st404  阅读(943)  评论(0编辑  收藏