-
Notifications
You must be signed in to change notification settings - Fork 548
Open
Description
Hi!
I have this program here:
#include <windows.h>
#include <iostream>
#include <vector>
#include <fstream>
// Typedefs for function pointers
// typedef HRESULT (__stdcall *ISVGImageFactoryCreate1Proxy_t)(void**);
typedef HRESULT (__stdcall *ISVGImageFactoryCreate1Proxy_t)(void**, char);
/*
void ISVGImageFactoryCreate1Proxy(longlong *param_1,undefined8 param_2)
{
longlong lVar1;
longlong *plVar2;
longlong *local_res8 [4];
plVar2 = Mso::SVG::ISVGImageFactory::Create(local_res8,param_2);
lVar1 = *plVar2;
*plVar2 = 0;
plVar2 = (longlong *)*param_1;
*param_1 = lVar1;
if (plVar2 != (longlong *)0x0) {
(**(code **)(*plVar2 + 8))();
}
plVar2 = local_res8[0];
if (local_res8[0] != (longlong *)0x0) {
local_res8[0] = (longlong *)0x0;
(**(code **)(*plVar2 + 8))();
}
return;
}
*/
// typedef HRESULT (__thiscall *CreateSVGImage_t)(void*, void**);
typedef void* (__thiscall *CreateSVGImage_t)(void*, void*);
typedef void (__thiscall *DestroyFunc)(void*);
HMODULE hDll;
ISVGImageFactoryCreate1Proxy_t ISVGImageFactoryCreate1Proxy;
/*
void PrintLastError(const char* message) {
DWORD errorCode = GetLastError();
LPVOID errorMessage;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&errorMessage, 0, NULL);
std::cerr << message << " Error Code: " << errorCode << " - " << (char*)errorMessage << std::endl;
LocalFree(errorMessage);
}
void PrintLastErrorWithModule() {
DWORD error = GetLastError(); // Get the last error code
if (error == 126) {
std::cerr << "Error 126: Module not found (missing dependency)" << std::endl;
} else if (error == 193) {
std::cerr << "Error 193: Incorrect architecture (x86 vs x64 mismatch)" << std::endl;
} else {
std::cerr << "Unknown error: " << error << std::endl;
}
LPVOID messageBuffer;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, 0, (LPTSTR)&messageBuffer, 0, NULL);
std::cerr << "Error Message: " << (char*)messageBuffer << std::endl;
LocalFree(messageBuffer);
}
*/
void PrintLastError() {
DWORD error = GetLastError();
if (error == 126) {
std::cerr << "Error 126: Module not found (missing dependency)" << std::endl;
} else if (error == 193) {
std::cerr << "Error 193: Incorrect architecture (x86 vs x64 mismatch)" << std::endl;
} else {
std::cerr << "Unknown error: " << error << std::endl;
}
LPVOID messageBuffer;
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, 0, (LPSTR)&messageBuffer, 0, NULL);
std::cerr << "Error Message: " << (char*)messageBuffer << std::endl;
LocalFree(messageBuffer);
}
// Function to print which module is failing
void PrintMissingDependency(const std::wstring& moduleName) {
HMODULE hModule = LoadLibraryExW(moduleName.c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
if (!hModule) {
DWORD error = GetLastError();
std::wcerr << L"Failed to load: " << moduleName << L" - Error " << error << std::endl;
} else {
std::wcout << L"Successfully loaded: " << moduleName << std::endl;
FreeLibrary(hModule);
}
}
/*
Microsoft (R) COFF/PE Dumper Version 14.42.34436.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file mso40uiWin32Client.dll
File Type: DLL
Image has the following dependencies:
KERNEL32.dll
gdiplus.dll
Mso30Win32Client.dll
Mso20Win32Client.dll
VCRUNTIME140_1.dll
VCRUNTIME140.dll
MSVCP140.dll
api-ms-win-crt-heap-l1-1-0.dll
api-ms-win-crt-convert-l1-1-0.dll
api-ms-win-crt-runtime-l1-1-0.dll
api-ms-win-crt-string-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-utility-l1-1-0.dll
api-ms-win-crt-math-l1-1-0.dll
api-ms-win-crt-filesystem-l1-1-0.dll
api-ms-win-crt-time-l1-1-0.dll
api-ms-win-crt-locale-l1-1-0.dll
api-ms-win-crt-multibyte-l1-1-0.dll
api-ms-win-crt-environment-l1-1-0.dll
Image has the following delay load dependencies:
dbghelp.dll
ADVAPI32.dll
d3d10_1.dll
d3d11.dll
d2d1.dll
DWrite.dll
dwmapi.dll
dxgi.dll
GDI32.dll
NInput.dll
OLEACC.dll
ole32.dll
USER32.dll
VERSION.dll
WindowsCodecs.dll
WINMM.dll
dcomp.dll
api-ms-win-core-winrt-string-l1-1-0.dll
api-ms-win-core-winrt-l1-1-0.dll
api-ms-win-core-winrt-error-l1-1-0.dll
MF.dll
MFPlat.DLL
msi.dll
MSIMG32.dll
OLEAUT32.dll
POWRPROF.dll
SHELL32.dll
SHLWAPI.dll
UIAutomationCore.DLL
UxTheme.dll
WINHTTP.dll
WTSAPI32.dll
XmlLite.dll
react-native-win32.dll
Microsoft.UI.Windowing.Core.dll
WebView2Loader.dll
Summary
4C000 .data
3000 .detourc
2000 .didat
85000 .pdata
6F6000 .rdata
3A000 .reloc
1000 .rsrc
972000 .text
*/
// Function to load DLL and get function pointers
int fuzz_init(void) {
// C:\Program Files\Microsoft Office\root\vfs\ProgramFilesCommonX64\Microsoft Shared\
// this was previously C:\\Program Files\\Microsoft Office\\root\\Office16\\
// SetDllDirectory("C:\\Program Files\\Microsoft Office\\root\\vfs\\ProgramFilesCommonX64\\Microsoft Shared\\"); // We need to look here
/*
hDll = LoadLibrary("MSOSVG.DLL");
if (!hDll) {
// std::cerr << "Failed to load MSOSVG.DLL\n";
PrintLastError("Failed to load MSOSVG.DLL\n");
return 1;
}*/
// HMODULE hDll = LoadLibraryEx("MSOSVG.dll", NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
// Try loading with explicit error detection
// HMODULE hDll = LoadLibraryExW(L"MSOSVG.dll", NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
// mso40uiWin32Client.dll
// HMODULE hDll = LoadLibraryExW(L"mso40uiWin32Client.dll", NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
HMODULE hDll = LoadLibraryW(L"MSOSVG.dll");
if (!hDll) {
std::cerr << "Failed to load MSOSVG.DLL" << std::endl;
PrintLastError();
// Now manually check each dependency
/*
std::vector<std::wstring> dependencies = {
L"KERNEL32.dll",
L"OLEAUT32.dll",
L"mso40uiWin32Client.dll",
L"Mso20Win32Client.dll",
L"VCRUNTIME140_1.dll",
L"VCRUNTIME140.dll",
L"MSVCP140.dll",
L"api-ms-win-crt-heap-l1-1-0.dll",
L"api-ms-win-crt-runtime-l1-1-0.dll",
L"api-ms-win-crt-string-l1-1-0.dll",
L"api-ms-win-crt-stdio-l1-1-0.dll",
L"api-ms-win-crt-math-l1-1-0.dll",
L"api-ms-win-crt-convert-l1-1-0.dll",
L"api-ms-win-crt-locale-l1-1-0.dll",
L"gfx.dll" // Delay-loaded dependency
};
};
std::vector<std::wstring> delay_load_dependencies = {
*/
std::vector<std::wstring> dependencies = {
L"KERNEL32.dll",
L"gdiplus.dll",
L"Mso30Win32Client.dll",
L"Mso20Win32Client.dll",
L"VCRUNTIME140_1.dll",
L"VCRUNTIME140.dll",
L"MSVCP140.dll",
L"api-ms-win-crt-heap-l1-1-0.dll",
L"api-ms-win-crt-convert-l1-1-0.dll",
L"api-ms-win-crt-runtime-l1-1-0.dll",
L"api-ms-win-crt-string-l1-1-0.dll",
L"api-ms-win-crt-stdio-l1-1-0.dll",
L"api-ms-win-crt-utility-l1-1-0.dll",
L"api-ms-win-crt-math-l1-1-0.dll",
L"api-ms-win-crt-filesystem-l1-1-0.dll",
L"api-ms-win-crt-time-l1-1-0.dll",
L"api-ms-win-crt-locale-l1-1-0.dll",
L"api-ms-win-crt-multibyte-l1-1-0.dll",
L"api-ms-win-crt-environment-l1-1-0.dll",
L"dbghelp.dll",
L"ADVAPI32.dll",
L"d3d10_1.dll",
L"d3d11.dll",
L"d2d1.dll",
L"DWrite.dll",
L"dwmapi.dll",
L"dxgi.dll",
L"GDI32.dll",
L"NInput.dll",
L"OLEACC.dll",
L"ole32.dll",
L"USER32.dll",
L"VERSION.dll",
L"WindowsCodecs.dll",
L"WINMM.dll",
L"dcomp.dll",
L"api-ms-win-core-winrt-string-l1-1-0.dll",
L"api-ms-win-core-winrt-l1-1-0.dll",
L"api-ms-win-core-winrt-error-l1-1-0.dll",
L"MF.dll",
L"MFPlat.DLL",
L"msi.dll",
L"MSIMG32.dll",
L"OLEAUT32.dll",
L"POWRPROF.dll",
L"SHELL32.dll",
L"SHLWAPI.dll",
L"UIAutomationCore.DLL",
L"UxTheme.dll",
L"WINHTTP.dll",
L"WTSAPI32.dll",
L"XmlLite.dll",
L"react-native-win32.dll",
L"Microsoft.UI.Windowing.Core.dll",
L"WebView2Loader.dll"
};
std::wcout << L"Checking dependencies...\n";
for (const auto& dep : dependencies) {
PrintMissingDependency(dep);
}
return 1;
}
// printf("Holy fuck!!!\n");
ISVGImageFactoryCreate1Proxy =
(ISVGImageFactoryCreate1Proxy_t) GetProcAddress(hDll, "ISVGImageFactoryCreate1Proxy");
if (!ISVGImageFactoryCreate1Proxy) {
std::cerr << "Failed to get function address for ISVGImageFactoryCreate1Proxy\n";
FreeLibrary(hDll);
return 1;
}
return 0;
}
// Function to read a file into a buffer
bool ReadFileToBuffer(const std::string& filename, std::vector<uint8_t>& buffer) {
std::ifstream file(filename, std::ios::binary);
if (!file) {
std::cerr << "Error: Could not open file: " << filename << "\n";
return false;
}
file.seekg(0, std::ios::end);
size_t fileSize = file.tellg();
file.seekg(0, std::ios::beg);
if (fileSize < 1) { // Ensure there is data
std::cerr << "Error: File must not be empty!\n";
return false;
}
buffer.resize(fileSize);
file.read(reinterpret_cast<char*>(buffer.data()), fileSize);
return true;
}
#include <objidl.h> // IStream
#include <ole2.h> // CreateStreamOnHGlobal
IStream* CreateMemoryStream(const std::vector<uint8_t>& data) {
IStream* stream = nullptr;
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, data.size());
if (hMem) {
void* pMem = GlobalLock(hMem);
if (pMem) {
memcpy(pMem, data.data(), data.size());
GlobalUnlock(hMem);
HRESULT hr = CreateStreamOnHGlobal(hMem, TRUE, &stream);
if (FAILED(hr)) {
std::cerr << "Failed to create memory stream!" << std::endl;
return nullptr;
}
}
}
return stream;
}
// Function to call CreateSVGImage
int fuzz_function(const std::vector<uint8_t>& svgData) {
void* factory = nullptr;
void* svgImage = nullptr;
HRESULT res;
printf("Called fuzz function...\n");
// Call the factory function to get an instance of ISVGImageFactory // NOTE: This actually returns void, therefore do not check res
// HRESULT res = ISVGImageFactoryCreate1Proxy(&factory);
ISVGImageFactoryCreate1Proxy(&factory, 0); // Need to pass in flags maybe???
//printf("Here is the factory pointer: %p\n", factory);
//if (FAILED(res) || !factory) {
if (!factory) {
std::cerr << "Error: Failed to get SVGImageFactory!\n";
return 1;
}
// Get the function pointer for CreateSVGImage from the vtable
void** vtable_ptr = *(void***)factory;
CreateSVGImage_t create_svg_func = (CreateSVGImage_t)vtable_ptr[3]; // Usually function at index 5
if (!create_svg_func) {
std::cerr << "Error: Failed to retrieve CreateSVGImage function pointer!\n";
return 1;
}
//printf("Address (this + 0x10): %p\n", (void*)((uintptr_t)factory + 0x10));
void* stream_ptr = *(void**)((uintptr_t)factory + 0x10);
//printf("Stream Pointer: %p\n", stream_ptr);
void** stream_location = (void**)((uintptr_t)factory + 0x10);
IStream* svgStream = CreateMemoryStream(svgData); // svgData is your SVG file contents
*stream_location = svgStream; // Assign our new memory stream to the factory
//printf("New Stream Pointer: %p\n", *stream_location);
*(IStream**)((char*)factory + 0x10) = svgStream;
/*
!!!!!!! IMPORTANT NOTES !!!!!!!
Now the value stored in stream_ptr should be the stream pointer aka a pointer to an ISTREAM object, which I assume is a stream which contains the actual SVG data.
This is based on educated guesses in this decompilation here:
undefined8 * __thiscall
Mso::SVG::SVGImageFactory::CreateSVGImage(SVGImageFactory *this,undefined8 *param_2)
{
loadmorestuff(param_2,*(longlong **)(this + 0x10),(char)this[0x18]);
return param_2;
}
The *(longlong **)(this + 0x10) stuff is basically just a pointer to the stream object.
This is later used here: Mso::SVG::GetUniqueIDFromStream(&local_70,somestreamstuff); in the function.
in GetUniqueIDFromStream we then have this:
void __cdecl Mso::SVG::GetUniqueIDFromStream(undefined8 *param_1,IStream *streamobj)
{
code *pcVar1;
int iVar2;
long lVar3;
long extraout_EAX;
undefined auStack_d8 [48];
undefined8 *local_a8;
undefined8 local_a0 [2];
undefined8 local_90;
undefined8 uStack_88;
undefined *local_78;
undefined8 uStack_70;
undefined4 local_68;
undefined4 local_64;
ulonglong local_18;
local_18 = __security_cookie ^ (ulonglong)auStack_d8;
local_90 = 0;
uStack_88 = 0;
local_a8 = param_1;
iVar2 = (**(code **)(*(longlong *)streamobj + 0x28))(streamobj,0,1,local_a0);
if (iVar2 < 0) {
Ofc::CHResultException::ThrowTag(iVar2,0x138d885);
lVar3 = extraout_EAX;
}
else {
local_68 = 0;
local_64 = 0;
local_78 = &DAT_efcdab8967452301;
uStack_70 = 0x1032547698badcfe;
Ofc::MD4Ctx::UpdateFromIStream((MD4Ctx *)&local_78,streamobj);
Ofc::MD4Ctx::Final((MD4Ctx *)&local_78,(MD4UID *)&local_90);
lVar3 = (**(code **)(*(longlong *)streamobj + 0x28))(streamobj,local_a0[0],0,0);
if (-1 < lVar3) {
*param_1 = local_90;
param_1[1] = uStack_88;
__security_check_cookie(local_18 ^ (ulonglong)auStack_d8);
return;
}
}
Ofc::CHResultException::ThrowTag(lVar3,0x138d886);
pcVar1 = (code *)swi(3);
(*pcVar1)();
return;
}
This is essentially just a caching function....
Ok, so now we have a sigsegv on
180006596 ff 15 3c CALL qword ptr [-> _guard_dispatch_icall ] undefined _guard_dispatch_icall(
21 14 00 = 180142750
18000659c 90 NOP
LAB_18000659d XREF[3]: 1800064ce (j) , 1800064e0 (j) ,
180006587 (j)
18000659d 48 8b c3 MOV RAX ,RBX
1800065a0 eb 09 JMP LAB_1800065ab
1800065a2 48 8b 44 MOV RAX ,qword ptr [RSP + 0x78 ]
24 78
1800065a7 48 83 20 AND qword ptr [RAX ],0x0
00
LAB_1800065ab XREF[1]: 1800065a0 (j)
1800065ab 48 8b 8c MOV suspected_filename ,qword ptr [RSP + local_18 ]
24 a0 00
00 00
1800065b3 48 33 cc XOR suspected_filename ,RSP
1800065b6 e8 95 a8 CALL __security_check_cookie undefined __security_check_cooki
13 00
on the and instruction. this is in loadmorestuff...
This is because the result fails here:
if (plVar2 == (longlong *)0x0) {
Ordinal_21217(0x1e3c3840,0);
pcVar1 = (code *)swi(3);
(*pcVar1)();
return;
}
(**(code **)(*plVar2 + 0x10))(plVar2);
plVar3 = theresul;
*suspected_filename = plVar2;
if (theresul != (longlong *)0x0) {
theresul = (longlong *)0x0;
(**(code **)(*plVar3 + 8))();
}
Here we have a function which basically just checks if we should use caching:
bVar4 = Mso::SVG::SVGImage::FUseCaching();
if (bVar4) {
Mso::SVG::GetUniqueIDFromStream(&local_70,somestreamstuff);
so therefore we can just patch this bullshit out and not use caching? That would be beneficial for fuzzing since it doesn't really make sense to use caching for fuzzing.
Here is the jnz call bullshit:
18000648e e8 99 eb CALL Mso::SVG::SVGImage::FUseCaching bool FUseCaching(void)
03 00
180006493 84 c0 TEST AL ,AL
180006495 75 4e JNZ LAB_1800064e5
180006497 ba 01 00 MOV somestreamstuff ,0x1
00 00
18000649c b9 a0 00 MOV suspected_filename ,0xa0
00 00
so therefore if we just patch the jnz out with nops, we should be good... correct?????
84 c0 75 4e ba 01 00 00 00 b9 a0 00 00 00
"84 c0 75 4e ba 01 00 00 00 b9 a0 00 00\x00"
The parameters to this function here: puVar1 = (undefined8 *)Mso::SVG::SVGImage::SVGImage(local_78,param_2,param_3);
are the following:
*/
// Call CreateSVGImage
// svgImage = create_svg_func(factory, &(void*)svgData.data()); // (void*)svgData.data()
printf("Calling create_svg_func\n");
create_svg_func(factory, &svgImage);
printf("Returned from the thing...\n");
//printf("Here is the svgImage: %p\n", svgImage);
//printf("Value at svgImage: %p\n", *svgImage); // Deref the shit.
if (FAILED(res) || !svgImage) {
//std::cerr << "CreateSVGImage failed!\n";
return 1;
}
//std::cout << "Successfully created SVGImage!\n";
// Cleanup: Destroy the created SVGImage if possible
DestroyFunc destroy_func = (DestroyFunc)vtable_ptr[0]; // Assuming first function in vtable is destroy
if (destroy_func) {
destroy_func(svgImage);
}
return 0;
}
// Main fuzzing function
__declspec(noinline) void __fastcall actual_stuff(char* filename) {
std::vector<uint8_t> buffer;
printf("Reading to file...\n");
if (!ReadFileToBuffer(filename, buffer)) {
return;
}
printf("Now calling fuzz...\n");
fuzz_function(buffer);
printf("After\n");
}
// Loop for continuous fuzzing
__declspec(noinline) void __fastcall loop(char* filename) {
printf("poopoooooooo\n");
actual_stuff(filename);
printf("After the fact...\n");
}
int main(int argc, char** argv) {
if (fuzz_init()) {
std::cerr << "Failed to initialize fuzzing setup\n";
return 0;
}
if (argc != 2) {
std::cerr << "Need to pass input file as command line argument!\n";
return 0;
}
while (1) {
printf("Calling the bullshit...\n");
loop(argv[1]);
}
FreeLibrary(hDll);
return 0;
}
when running normally without afl-fuzz, the binary works normally and loops in the loop function, however when running with this command line:
afl-fuzz.exe -T 100000 -d -i corpus -o findings -y -t 60000 -f input.data -- -instrument_module MSOSVG.DLL -iterations 100000 -target_module fuzzer.exe -target_offset 0x2100 -nargs 1 -persist -- ".\fuzzer.exe" "@@"
I get the following output:
afl-fuzz.exe -T 100000 -d -i corpus -o findings -y -t 60000 -f input.data -- -instrument_module MSOSVG.DLL -iterations 100000 -target_module fuzzer.exe -target_offset 0x2100 -nargs 1 -persist -- ".\fuzzer.exe" "@@"
WinAFL 1.17 by <ifratric@google.com>
Based on AFL 2.43b by <lcamtuf@google.com>
[+] You have 12 CPU cores with average utilization of 0%.
[+] Try parallel jobs - see afl_docs\parallel_fuzzing.txt.
[*] Checking CPU core loadout...
[+] Found a free CPU core, binding to #0.
[+] Process affinity is set to 1.
[*] Setting up output directories...
[+] Output directory exists but deemed OK to reuse.
[*] Deleting old session data...
[+] Output dir cleanup successful.
[*] Scanning 'corpus'...
[+] No auto-generated dictionary tokens to reuse.
[*] Creating hard links for all input files...
[*] Attempting dry run with 'id_000000'...
Calling the bullshit...
Instrumented module MSOSVG.DLL, code size: 1339392
poopoooooooo
Reading to file...
Now calling fuzz...
Called fuzz function...
Calling create_svg_func
[!] WARNING: Process exit during target function
[-] The program took more than 60000 ms to process one of the initial test cases.
In WinAFL, this error could also mean incorrect instrumentation params.
Please make sure instrumentation runs correctly using the debug mode
(see the README) before attempting to run afl-fuzz.
[-] PROGRAM ABORT : Test case 'id_000000' results in a timeout
Location : perform_dry_run(), C:\Users\elsku\newtools\aflfuzz\winafl\afl-fuzz.c:3254
so it hangs in the call to the internal dll function while completing normally during a normal program execution. I am not sure if this is a tinyinst bug or a bug in afl-fuzz.
I have attached all of the files which I used. I used the most recent commit of winafl.
I also tried to run with Dynamorio, but I think I ran into #454
The attachment was too large so I have a attached a link to my github here: https://github.com/personnumber3377/debug_files
Metadata
Metadata
Assignees
Labels
No labels