implemented wrapping of common 'save' methods
This commit is contained in:
parent
20c916077a
commit
a93c772b90
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,4 +1,6 @@
|
|||||||
*.o
|
.gitignore
|
||||||
|
|
||||||
|
.o
|
||||||
*.so
|
*.so
|
||||||
*.a
|
*.a
|
||||||
*.test
|
*.test
|
||||||
|
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"files.associations": {
|
|
||||||
"cstdlib": "c",
|
|
||||||
"memory": "cpp",
|
|
||||||
"semaphore": "cpp",
|
|
||||||
"stop_token": "cpp",
|
|
||||||
"iostream": "cpp"
|
|
||||||
}
|
|
||||||
}
|
|
17
ABSTRACT.md
Normal file
17
ABSTRACT.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Windows Binary Fuzzing
|
||||||
|
|
||||||
|
Modern-day fuzzing is one of the most efficient techniques to automatically detect bugs and vulnerabilities in software projects [1]. It works by automatically feeding pseudo-randomly generated input data to the target program under test. However, most fuzzing techniques are only possible for target programs with source code and without a GUI [2]. This is because closed-source programs and programs with a GUI cannot easily be harnessed by fuzzers. This means, that the fuzzer cannot automatically find a good way to feed input into the program. In the scope of this thesis/project, closed-source GUI programs on Windows should be fuzzed. Contrary to the Linux and open-source community, the Windows ecosystem has received little attention. Therefore, in the scope of this project, a tool should be developed, which automatically harnesses and fuzzes Windows applications. To achieve this, simple binary rewriting frameworks [3] may be used to replace GUI file opening dialoges with an automatic way to feed file input into a program. Then, well-established fuzzing tools [4,5,6] can be used to fuzz multiple Windows-only programs. This should provide a first look into, whether the applications in the Windows ecosystem are as vulnerable as expected.
|
||||||
|
|
||||||
|
References:
|
||||||
|
|
||||||
|
[1] https://github.com/google/oss-fuzz
|
||||||
|
|
||||||
|
[2] https://www.usenix.org/system/files/usenixsecurity24-schilling.pdf
|
||||||
|
|
||||||
|
[3] https://ieeexplore.ieee.org/abstract/document/8023154/
|
||||||
|
|
||||||
|
[4] https://github.com/googleprojectzero/winafl
|
||||||
|
|
||||||
|
[5] https://par.nsf.gov/servlets/purl/10308834
|
||||||
|
|
||||||
|
[6] https://www.usenix.org/system/files/sec21-nagy.pdf
|
@ -4,12 +4,17 @@
|
|||||||
|
|
||||||
- [x] `GetOpenFileNameA` (ANSI)
|
- [x] `GetOpenFileNameA` (ANSI)
|
||||||
- [x] `GetOpenFileNameW` (UTF-16)
|
- [x] `GetOpenFileNameW` (UTF-16)
|
||||||
|
- [x] `GetSaveFileNameA` (ANSI)
|
||||||
|
- [x] `GetSaveFileNameW` (UTF-16)
|
||||||
- [x] `IFileOpenDialog`
|
- [x] `IFileOpenDialog`
|
||||||
|
- [x] `IFileSaveDialog`
|
||||||
- [x] `QFileDialog::getOpenFileName`
|
- [x] `QFileDialog::getOpenFileName`
|
||||||
- [ ] `QFileDialog::getOpenFileNames`
|
- [ ] `QFileDialog::getOpenFileNames`
|
||||||
- [x] `QFileDialog::getOpenFileUrl`
|
- [x] `QFileDialog::getOpenFileUrl`
|
||||||
- [ ] `QFileDialog::getOpenFileUrls`
|
- [ ] `QFileDialog::getOpenFileUrls`
|
||||||
- [ ] `QFileDialog::getOpenFileContent`
|
- [ ] `QFileDialog::getOpenFileContent`
|
||||||
|
- [x] `QFileDialog::getSaveFileName`
|
||||||
|
- [x] `QFileDialog::getSaveFileUrl`
|
||||||
- [ ] `wxFileDialog`
|
- [ ] `wxFileDialog`
|
||||||
|
|
||||||
## Build scripts
|
## Build scripts
|
||||||
|
@ -21,8 +21,11 @@ const char *MANGLED_QFileDialog_getOpenFileNames = "?getOpenFileNames@QFileDialo
|
|||||||
const char *MANGLED_QFileDialog_getOpenFileUrl = "?getOpenFileUrl@QFileDialog@@SA?AVQUrl@@PEAVQWidget@@AEBVQString@@AEBV2@1PEAV4@V?$QFlags@W4Option@QFileDialog@@@@AEBV?$QList@VQString@@@@@Z";
|
const char *MANGLED_QFileDialog_getOpenFileUrl = "?getOpenFileUrl@QFileDialog@@SA?AVQUrl@@PEAVQWidget@@AEBVQString@@AEBV2@1PEAV4@V?$QFlags@W4Option@QFileDialog@@@@AEBV?$QList@VQString@@@@@Z";
|
||||||
const char *MANGLED_QFileDialog_getOpenFileUrls = "?getOpenFileUrls@QFileDialog@@SA?AV?$QList@VQUrl@@@@PEAVQWidget@@AEBVQString@@AEBVQUrl@@1PEAV4@V?$QFlags@W4Option@QFileDialog@@@@AEBV?$QList@VQString@@@@@Z";
|
const char *MANGLED_QFileDialog_getOpenFileUrls = "?getOpenFileUrls@QFileDialog@@SA?AV?$QList@VQUrl@@@@PEAVQWidget@@AEBVQString@@AEBVQUrl@@1PEAV4@V?$QFlags@W4Option@QFileDialog@@@@AEBV?$QList@VQString@@@@@Z";
|
||||||
const char *MANGLED_QFileDialog_getOpenFileContent = "?getOpenFileContent@QFileDialog@@SAXAEBVQString@@AEBV?$function@$$A6AXAEBVQString@@AEBVQByteArray@@@Z@std@@PEAVQWidget@@@Z";
|
const char *MANGLED_QFileDialog_getOpenFileContent = "?getOpenFileContent@QFileDialog@@SAXAEBVQString@@AEBV?$function@$$A6AXAEBVQString@@AEBVQByteArray@@@Z@std@@PEAVQWidget@@@Z";
|
||||||
|
const char *MANGLED_QFileDialog_getSaveFileName = "?getSaveFileName@QFileDialog@@SA?AVQString@@PEAVQWidget@@AEBV2@11PEAV2@V?$QFlags@W4Option@QFileDialog@@@@@Z";
|
||||||
|
const char *MANGLED_QFileDialog_getSaveFileUrl = "?getSaveFileUrl@QFileDialog@@SA?AVQUrl@@PEAVQWidget@@AEBVQString@@AEBV2@1PEAV4@V?$QFlags@W4Option@QFileDialog@@@@AEBV?$QList@VQString@@@@@Z";
|
||||||
|
|
||||||
char *CUSTOM_FILE = "C:\\Users\\vboxuser\\Downloads\\spoofed_number.txt";
|
char *OPEN_FILE = "C:\\Users\\vboxuser\\Downloads\\spoofed_number.txt";
|
||||||
|
char *SAVE_FILE = "C:\\Users\\vboxuser\\Downloads\\spoofed_save.txt";
|
||||||
|
|
||||||
// Function pointers for functions we need to call ourselves
|
// Function pointers for functions we need to call ourselves
|
||||||
static void (*fn_QString_const)(void *qstring, const char *str) = NULL;
|
static void (*fn_QString_const)(void *qstring, const char *str) = NULL;
|
||||||
@ -46,9 +49,11 @@ static void pre_IFileOpenDialog_GetResult(void *wrapctx, void **user_data);
|
|||||||
static void pre_IFileOpenDialog_Show(void *wrapctx, void **user_data);
|
static void pre_IFileOpenDialog_Show(void *wrapctx, void **user_data);
|
||||||
|
|
||||||
static HRESULT custom_IFileDialog_Show(void *, void *);
|
static HRESULT custom_IFileDialog_Show(void *, void *);
|
||||||
static HRESULT custom_IFileDialog_GetResult(void *, IShellItem **ppsitem);
|
static HRESULT custom_IFileOpenDialog_GetResult(void *, IShellItem **ppsitem);
|
||||||
|
static HRESULT custom_IFileSaveDialog_GetResult(void *, IShellItem **ppsitem);
|
||||||
|
|
||||||
struct IFileOpenDialogVtbl customFODVtbl = {};
|
struct IFileOpenDialogVtbl customFODVtbl = {};
|
||||||
|
struct IFileSaveDialogVtbl customFSDVtbl = {};
|
||||||
|
|
||||||
// --- drwrap Callbacks for WinAPI Functions ---
|
// --- drwrap Callbacks for WinAPI Functions ---
|
||||||
|
|
||||||
@ -57,7 +62,7 @@ static void pre_GetOpenFileNameA(void *wrapctx, void **user_data)
|
|||||||
OPENFILENAMEA *ofn = (OPENFILENAMEA *)drwrap_get_arg(wrapctx, 0);
|
OPENFILENAMEA *ofn = (OPENFILENAMEA *)drwrap_get_arg(wrapctx, 0);
|
||||||
if (ofn && ofn->lpstrFile)
|
if (ofn && ofn->lpstrFile)
|
||||||
{
|
{
|
||||||
strncpy(ofn->lpstrFile, CUSTOM_FILE, ofn->nMaxFile - 1);
|
strncpy(ofn->lpstrFile, OPEN_FILE, ofn->nMaxFile - 1);
|
||||||
ofn->lpstrFile[ofn->nMaxFile - 1] = '\0';
|
ofn->lpstrFile[ofn->nMaxFile - 1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +74,31 @@ static void pre_GetOpenFileNameW(void *wrapctx, void **user_data)
|
|||||||
OPENFILENAMEW *ofn = (OPENFILENAMEW *)drwrap_get_arg(wrapctx, 0);
|
OPENFILENAMEW *ofn = (OPENFILENAMEW *)drwrap_get_arg(wrapctx, 0);
|
||||||
if (ofn && ofn->lpstrFile)
|
if (ofn && ofn->lpstrFile)
|
||||||
{
|
{
|
||||||
mbstowcs(ofn->lpstrFile, CUSTOM_FILE, ofn->nMaxFile - 1);
|
mbstowcs(ofn->lpstrFile, OPEN_FILE, ofn->nMaxFile - 1);
|
||||||
|
ofn->lpstrFile[ofn->nMaxFile - 1] = L'\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
drwrap_skip_call(wrapctx, (void *)1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pre_GetSaveFileNameA(void *wrapctx, void **user_data)
|
||||||
|
{
|
||||||
|
OPENFILENAMEA *ofn = (OPENFILENAMEA *)drwrap_get_arg(wrapctx, 0);
|
||||||
|
if (ofn && ofn->lpstrFile)
|
||||||
|
{
|
||||||
|
strncpy(ofn->lpstrFile, SAVE_FILE, ofn->nMaxFile - 1);
|
||||||
|
ofn->lpstrFile[ofn->nMaxFile - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
drwrap_skip_call(wrapctx, (void *)1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pre_GetSaveFileNameW(void *wrapctx, void **user_data)
|
||||||
|
{
|
||||||
|
OPENFILENAMEW *ofn = (OPENFILENAMEW *)drwrap_get_arg(wrapctx, 0);
|
||||||
|
if (ofn && ofn->lpstrFile)
|
||||||
|
{
|
||||||
|
mbstowcs(ofn->lpstrFile, SAVE_FILE, ofn->nMaxFile - 1);
|
||||||
ofn->lpstrFile[ofn->nMaxFile - 1] = L'\0';
|
ofn->lpstrFile[ofn->nMaxFile - 1] = L'\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +113,7 @@ static void pre_QFileDialog_getOpenFileName(void *wrapctx, void **user_data)
|
|||||||
return;
|
return;
|
||||||
// The return value is passed as a pointer in the first argument (sret)
|
// The return value is passed as a pointer in the first argument (sret)
|
||||||
void *qstring_ret_ptr = (void *)drwrap_get_arg(wrapctx, 0);
|
void *qstring_ret_ptr = (void *)drwrap_get_arg(wrapctx, 0);
|
||||||
fn_QString_const(qstring_ret_ptr, CUSTOM_FILE);
|
fn_QString_const(qstring_ret_ptr, OPEN_FILE);
|
||||||
drwrap_skip_call(wrapctx, NULL, 0);
|
drwrap_skip_call(wrapctx, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +124,46 @@ static void pre_QFileDialog_getOpenFileUrl(void *wrapctx, void **user_data)
|
|||||||
|
|
||||||
const char *prefix = "file:///";
|
const char *prefix = "file:///";
|
||||||
char urlbuf[MAX_PATH + 10];
|
char urlbuf[MAX_PATH + 10];
|
||||||
snprintf(urlbuf, sizeof(urlbuf), "%s%s", prefix, CUSTOM_FILE);
|
snprintf(urlbuf, sizeof(urlbuf), "%s%s", prefix, OPEN_FILE);
|
||||||
|
|
||||||
|
// Replace backslashes for URL format
|
||||||
|
for (char *p = urlbuf; *p; ++p)
|
||||||
|
{
|
||||||
|
if (*p == '\\')
|
||||||
|
*p = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a temporary QString for the URL
|
||||||
|
char local_qstring[24]; // Allocate space for a QString object on the stack
|
||||||
|
fn_QString_const(local_qstring, urlbuf);
|
||||||
|
|
||||||
|
// Get the return QUrl object pointer (sret)
|
||||||
|
void *qurl_ret_ptr = (void *)drwrap_get_arg(wrapctx, 0);
|
||||||
|
fn_QUrl_const(qurl_ret_ptr, local_qstring, 0); // 0 is TolerantMode
|
||||||
|
|
||||||
|
drwrap_skip_call(wrapctx, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pre_QFileDialog_getSaveFileName(void *wrapctx, void **user_data)
|
||||||
|
{
|
||||||
|
if (fn_QString_const == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// The return value is passed as a pointer in the first argument (sret)
|
||||||
|
void *qstring_ret_ptr = (void *)drwrap_get_arg(wrapctx, 0);
|
||||||
|
fn_QString_const(qstring_ret_ptr, SAVE_FILE);
|
||||||
|
drwrap_skip_call(wrapctx, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pre_QFileDialog_getSaveFileUrl(void *wrapctx, void **user_data)
|
||||||
|
{
|
||||||
|
if (fn_QString_const == NULL || fn_QUrl_const == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const char *prefix = "file:///";
|
||||||
|
char urlbuf[MAX_PATH + 10];
|
||||||
|
snprintf(urlbuf, sizeof(urlbuf), "%s%s", prefix, SAVE_FILE);
|
||||||
|
|
||||||
// Replace backslashes for URL format
|
// Replace backslashes for URL format
|
||||||
for (char *p = urlbuf; *p; ++p)
|
for (char *p = urlbuf; *p; ++p)
|
||||||
{
|
{
|
||||||
@ -116,25 +184,54 @@ static void pre_QFileDialog_getOpenFileUrl(void *wrapctx, void **user_data)
|
|||||||
|
|
||||||
// --- COM Wrapping Logic ---
|
// --- COM Wrapping Logic ---
|
||||||
|
|
||||||
|
const int TYPE_IFileOpenDialog = 1;
|
||||||
|
const int TYPE_IFileSaveDialog = 2;
|
||||||
|
|
||||||
|
struct CoCreateInstance_data {
|
||||||
|
int type;
|
||||||
|
void *dialog;
|
||||||
|
};
|
||||||
|
|
||||||
static void pre_CoCreateInstance(void *wrapctx, void **user_data)
|
static void pre_CoCreateInstance(void *wrapctx, void **user_data)
|
||||||
{
|
{
|
||||||
|
*user_data = NULL;
|
||||||
|
|
||||||
// Arguments: rclsid, pUnkOuter, dwClsContext, riid, ppv
|
// Arguments: rclsid, pUnkOuter, dwClsContext, riid, ppv
|
||||||
const IID *riid = (const IID *)drwrap_get_arg(wrapctx, 3);
|
const IID *riid = (const IID *)drwrap_get_arg(wrapctx, 3);
|
||||||
const CLSID *rclsid = (const CLSID *)drwrap_get_arg(wrapctx, 0);
|
const CLSID *rclsid = (const CLSID *)drwrap_get_arg(wrapctx, 0);
|
||||||
|
if (!rclsid || !riid) return;
|
||||||
|
|
||||||
// We are only interested in the creation of a FileOpenDialog
|
int type = 0;
|
||||||
if (rclsid != NULL && IsEqualIID(rclsid, &CLSID_FileOpenDialog) &&
|
void *dialog = NULL;
|
||||||
riid != NULL && IsEqualIID(riid, &IID_IFileOpenDialog))
|
|
||||||
|
if (IsEqualIID(rclsid, &CLSID_FileOpenDialog) && IsEqualIID(riid, &IID_IFileOpenDialog))
|
||||||
{
|
{
|
||||||
|
|
||||||
dr_printf("drwrap: Intercepting CoCreateInstance for FileOpenDialog\n");
|
dr_printf("drwrap: Intercepting CoCreateInstance for FileOpenDialog\n");
|
||||||
// Pass the pointer to the output interface pointer (ppv) to the post-hook
|
// Pass the pointer to the output interface pointer (ppv) to the post-hook
|
||||||
*user_data = drwrap_get_arg(wrapctx, 4);
|
dialog = drwrap_get_arg(wrapctx, 4);
|
||||||
|
type = TYPE_IFileOpenDialog;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (IsEqualIID(rclsid, &CLSID_FileSaveDialog) && IsEqualIID(riid, &IID_IFileSaveDialog))
|
||||||
{
|
{
|
||||||
*user_data = NULL;
|
dr_printf("drwrap: Intercepting CoCreateInstance for FileSaveDialog\n");
|
||||||
|
// Pass the pointer to the output interface pointer (ppv) to the post-hook
|
||||||
|
dialog = drwrap_get_arg(wrapctx, 4);
|
||||||
|
type = TYPE_IFileSaveDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!type || !dialog) return;
|
||||||
|
|
||||||
|
struct CoCreateInstance_data *m_user_data = malloc(sizeof(*m_user_data));
|
||||||
|
if (!m_user_data) {
|
||||||
|
perror("malloc");
|
||||||
|
dr_exit_process(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_user_data->type = type;
|
||||||
|
m_user_data->dialog = dialog;
|
||||||
|
|
||||||
|
*user_data = (void *)m_user_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void post_CoCreateInstance(void *wrapctx, void *user_data)
|
static void post_CoCreateInstance(void *wrapctx, void *user_data)
|
||||||
@ -143,31 +240,76 @@ static void post_CoCreateInstance(void *wrapctx, void *user_data)
|
|||||||
if (!user_data)
|
if (!user_data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
struct CoCreateInstance_data m_user_data;
|
||||||
|
m_user_data = *(struct CoCreateInstance_data *)user_data;
|
||||||
|
|
||||||
|
free(user_data);
|
||||||
|
|
||||||
|
|
||||||
HRESULT hr = (HRESULT)drwrap_get_retval(wrapctx);
|
HRESULT hr = (HRESULT)drwrap_get_retval(wrapctx);
|
||||||
if (SUCCEEDED(hr))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
// The user_data is the ppv argument from the pre-hook
|
if (m_user_data.type == TYPE_IFileOpenDialog) {
|
||||||
IFileOpenDialog **ppv = (IFileOpenDialog **)user_data;
|
IFileOpenDialog **ppv = (IFileOpenDialog **)m_user_data.dialog;
|
||||||
if (ppv && *ppv)
|
if (!ppv || !*ppv) return;
|
||||||
{
|
|
||||||
IFileOpenDialog *fod = *ppv;
|
IFileOpenDialog *fod = *ppv;
|
||||||
|
|
||||||
|
WCHAR wfile[MAX_PATH];
|
||||||
|
mbstowcs(wfile, OPEN_FILE, MAX_PATH - 1);
|
||||||
|
wfile[MAX_PATH - 1] = L'\0';
|
||||||
|
|
||||||
|
fod->lpVtbl->SetFileName(fod, wfile);
|
||||||
|
|
||||||
customFODVtbl = *fod->lpVtbl;
|
customFODVtbl = *fod->lpVtbl;
|
||||||
customFODVtbl.Show = custom_IFileDialog_Show;
|
customFODVtbl.Show = custom_IFileDialog_Show;
|
||||||
customFODVtbl.GetResult = custom_IFileDialog_GetResult;
|
customFODVtbl.GetResult = custom_IFileOpenDialog_GetResult;
|
||||||
|
|
||||||
fod->lpVtbl = &customFODVtbl;
|
fod->lpVtbl = &customFODVtbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_user_data.type == TYPE_IFileSaveDialog) {
|
||||||
|
IFileSaveDialog **ppv = (IFileSaveDialog **)m_user_data.dialog;
|
||||||
|
if (!ppv || !*ppv) return;
|
||||||
|
|
||||||
|
IFileSaveDialog *fsd = *ppv;
|
||||||
|
|
||||||
|
WCHAR wfile[MAX_PATH];
|
||||||
|
mbstowcs(wfile, SAVE_FILE, MAX_PATH - 1);
|
||||||
|
wfile[MAX_PATH - 1] = L'\0';
|
||||||
|
|
||||||
|
customFSDVtbl = *fsd->lpVtbl;
|
||||||
|
customFSDVtbl.Show = custom_IFileDialog_Show;
|
||||||
|
customFSDVtbl.GetResult = custom_IFileSaveDialog_GetResult;
|
||||||
|
|
||||||
|
fsd->lpVtbl = &customFSDVtbl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT custom_IFileDialog_Show(void *self, void *b) {
|
static HRESULT custom_IFileDialog_Show(void *self, void *b)
|
||||||
|
{
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT custom_IFileDialog_GetResult(void *self, IShellItem **ppsitem) {
|
static HRESULT custom_IFileSaveDialog_GetResult(void *self, IShellItem **ppsitem)
|
||||||
|
{
|
||||||
WCHAR file[MAX_PATH];
|
WCHAR file[MAX_PATH];
|
||||||
mbstowcs(file, CUSTOM_FILE, MAX_PATH);
|
mbstowcs(file, SAVE_FILE, MAX_PATH);
|
||||||
|
file[MAX_PATH - 1] = L'\0';
|
||||||
|
|
||||||
|
HANDLE handle = CreateFileA(SAVE_FILE, GENERIC_ALL,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
CloseHandle(handle);
|
||||||
|
|
||||||
|
return fn_SHCreateItemFromParsingName(file, NULL, &IID_IShellItem, (void **)ppsitem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT custom_IFileOpenDialog_GetResult(void *self, IShellItem **ppsitem)
|
||||||
|
{
|
||||||
|
WCHAR file[MAX_PATH];
|
||||||
|
mbstowcs(file, OPEN_FILE, MAX_PATH);
|
||||||
file[MAX_PATH - 1] = L'\0';
|
file[MAX_PATH - 1] = L'\0';
|
||||||
|
|
||||||
return fn_SHCreateItemFromParsingName(file, NULL, &IID_IShellItem, (void **)ppsitem);
|
return fn_SHCreateItemFromParsingName(file, NULL, &IID_IShellItem, (void **)ppsitem);
|
||||||
@ -190,11 +332,11 @@ static void event_module_load(void *drcontext, const module_data_t *mod, bool lo
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GET_FUNCTION_POINTER(var, name) \
|
#define GET_FUNCTION_POINTER(var, name) \
|
||||||
{ \
|
{ \
|
||||||
if (var == NULL) \
|
if (var == NULL) \
|
||||||
{ \
|
{ \
|
||||||
var = (void *)dr_get_proc_address(mod->handle, name); \
|
var = (void *)dr_get_proc_address(mod->handle, name); \
|
||||||
if (var != NULL) \
|
if (var != NULL) \
|
||||||
dr_printf("Found function pointer %s in %s\n", name, dr_module_preferred_name(mod)); \
|
dr_printf("Found function pointer %s in %s\n", name, dr_module_preferred_name(mod)); \
|
||||||
} \
|
} \
|
||||||
@ -203,18 +345,21 @@ static void event_module_load(void *drcontext, const module_data_t *mod, bool lo
|
|||||||
// WinAPI Hooks
|
// WinAPI Hooks
|
||||||
WRAP_FUNCTION("GetOpenFileNameA", pre_GetOpenFileNameA, NULL);
|
WRAP_FUNCTION("GetOpenFileNameA", pre_GetOpenFileNameA, NULL);
|
||||||
WRAP_FUNCTION("GetOpenFileNameW", pre_GetOpenFileNameW, NULL);
|
WRAP_FUNCTION("GetOpenFileNameW", pre_GetOpenFileNameW, NULL);
|
||||||
|
WRAP_FUNCTION("GetSaveFileNameA", pre_GetSaveFileNameA, NULL);
|
||||||
|
WRAP_FUNCTION("GetSaveFileNameW", pre_GetSaveFileNameW, NULL);
|
||||||
WRAP_FUNCTION("CoCreateInstance", pre_CoCreateInstance, post_CoCreateInstance);
|
WRAP_FUNCTION("CoCreateInstance", pre_CoCreateInstance, post_CoCreateInstance);
|
||||||
|
|
||||||
// Qt Hooks
|
// Qt Hooks
|
||||||
WRAP_FUNCTION(MANGLED_QFileDialog_getOpenFileName, pre_QFileDialog_getOpenFileName, NULL);
|
WRAP_FUNCTION(MANGLED_QFileDialog_getOpenFileName, pre_QFileDialog_getOpenFileName, NULL);
|
||||||
WRAP_FUNCTION(MANGLED_QFileDialog_getOpenFileUrl, pre_QFileDialog_getOpenFileUrl, NULL);
|
WRAP_FUNCTION(MANGLED_QFileDialog_getOpenFileUrl, pre_QFileDialog_getOpenFileUrl, NULL);
|
||||||
|
WRAP_FUNCTION(MANGLED_QFileDialog_getSaveFileName, pre_QFileDialog_getSaveFileName, NULL);
|
||||||
|
WRAP_FUNCTION(MANGLED_QFileDialog_getSaveFileUrl, pre_QFileDialog_getSaveFileUrl, NULL);
|
||||||
|
|
||||||
// Get pointers to functions we need to call ourselves
|
// Get pointers to functions we need to call ourselves
|
||||||
GET_FUNCTION_POINTER(fn_QString_const, MANGLED_QString_const);
|
GET_FUNCTION_POINTER(fn_QString_const, MANGLED_QString_const);
|
||||||
GET_FUNCTION_POINTER(fn_QUrl_const, MANGLED_QUrl_const);
|
GET_FUNCTION_POINTER(fn_QUrl_const, MANGLED_QUrl_const);
|
||||||
GET_FUNCTION_POINTER(fn_CoTaskMemAlloc, "CoTaskMemAlloc");
|
GET_FUNCTION_POINTER(fn_CoTaskMemAlloc, "CoTaskMemAlloc");
|
||||||
GET_FUNCTION_POINTER(fn_SHCreateItemFromParsingName, "SHCreateItemFromParsingName");
|
GET_FUNCTION_POINTER(fn_SHCreateItemFromParsingName, "SHCreateItemFromParsingName");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void event_exit(void)
|
static void event_exit(void)
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
cl /Fe:compiled\Foo.exe source\Foo.c /Zi /Od /link /MACHINE:X64
|
cl /Fe:compiled\Foo.exe source\Foo.c /Zi /Od /link /MACHINE:X64
|
||||||
|
|
||||||
cl /Fe:compiled\GetOpenFileNameA.exe comdlg32.lib source\GetOpenFileNameA.c /Zi /Od /link /MACHINE:X64
|
cl /Fe:compiled\GetOpenFileNameA.exe comdlg32.lib source\GetOpenFileNameA.c /Zi /Od /link /MACHINE:X64
|
||||||
|
|
||||||
cl /Fe:compiled\GetOpenFileNameW.exe comdlg32.lib source\GetOpenFileNameA.c /Zi /Od /link /MACHINE:X64
|
cl /Fe:compiled\GetOpenFileNameW.exe comdlg32.lib source\GetOpenFileNameA.c /Zi /Od /link /MACHINE:X64
|
||||||
|
cl /Fe:compiled\GetSaveFileNameA.exe comdlg32.lib source\GetSaveFileNameA.c /Zi /Od /link /MACHINE:X64
|
||||||
cl /Fe:compiled\IFileDialog.exe uuid.lib ole32.lib source\IFileDialog.c /Zi /Od /link /MACHINE:X64
|
cl /Fe:compiled\GetSaveFileNameW.exe comdlg32.lib source\GetSaveFileNameA.c /Zi /Od /link /MACHINE:X64
|
||||||
|
cl /Fe:compiled\IFileOpenDialog.exe uuid.lib ole32.lib source\IFileOpenDialog.c /Zi /Od /link /MACHINE:X64
|
||||||
|
cl /Fe:compiled\IFileSaveDialog.exe uuid.lib ole32.lib source\IFileSaveDialog.c /Zi /Od /link /MACHINE:X64
|
||||||
|
|
||||||
qmake source\QT_getOpenFileContent.pro
|
qmake source\QT_getOpenFileContent.pro
|
||||||
nmake
|
nmake
|
||||||
@ -21,5 +22,11 @@ nmake
|
|||||||
qmake source\QT_getOpenFileUrls.pro
|
qmake source\QT_getOpenFileUrls.pro
|
||||||
nmake
|
nmake
|
||||||
|
|
||||||
|
qmake source\QT_getSaveFileName.pro
|
||||||
|
nmake
|
||||||
|
|
||||||
|
qmake source\QT_getSaveFileUrl.pro
|
||||||
|
nmake
|
||||||
|
|
||||||
qmake source\QT_TestLib.pro
|
qmake source\QT_TestLib.pro
|
||||||
nmake -f Makefile.Debug
|
nmake -f Makefile.Debug
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
programs/compiled/GetSaveFileNameA.exe
Normal file
BIN
programs/compiled/GetSaveFileNameA.exe
Normal file
Binary file not shown.
BIN
programs/compiled/GetSaveFileNameW.exe
Normal file
BIN
programs/compiled/GetSaveFileNameW.exe
Normal file
Binary file not shown.
BIN
programs/compiled/IFileOpenDialog.exe
Normal file
BIN
programs/compiled/IFileOpenDialog.exe
Normal file
Binary file not shown.
BIN
programs/compiled/IFileSaveDialog.exe
Normal file
BIN
programs/compiled/IFileSaveDialog.exe
Normal file
Binary file not shown.
Binary file not shown.
BIN
programs/compiled/QT_getSaveFileName.exe
Normal file
BIN
programs/compiled/QT_getSaveFileName.exe
Normal file
Binary file not shown.
BIN
programs/compiled/QT_getSaveFileUrl.exe
Normal file
BIN
programs/compiled/QT_getSaveFileUrl.exe
Normal file
Binary file not shown.
42
programs/source/GetSaveFileNameA.c
Normal file
42
programs/source/GetSaveFileNameA.c
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <commdlg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
char file[MAX_PATH] = {0};
|
||||||
|
|
||||||
|
OPENFILENAME ofn = {
|
||||||
|
.lStructSize = sizeof(ofn),
|
||||||
|
.lpstrFilter = "Text Files\0*.txt\0All Files\0*.*\0",
|
||||||
|
.lpstrFile = file,
|
||||||
|
.nMaxFile = MAX_PATH,
|
||||||
|
.lpstrTitle = "Save File As",
|
||||||
|
.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT
|
||||||
|
};
|
||||||
|
|
||||||
|
int res = GetSaveFileNameA(&ofn);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
puts("File selection cancelled or failed!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *f = fopen(ofn.lpstrFile, "w");
|
||||||
|
if (!f) {
|
||||||
|
perror("Error opening file for writing");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fprintf(f, "foo") < 0) {
|
||||||
|
perror("Error writing to file");
|
||||||
|
fclose(f);
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
printf("Successfully wrote \"foo\" to '%s'.\n", ofn.lpstrFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
42
programs/source/GetSaveFileNameW.c
Normal file
42
programs/source/GetSaveFileNameW.c
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <commdlg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
WCHAR file[MAX_PATH] = {0};
|
||||||
|
|
||||||
|
OPENFILENAMEW ofn = {
|
||||||
|
.lStructSize = sizeof(ofn),
|
||||||
|
.lpstrFilter = L"Text Files\0*.txt\0All Files\0*.*\0",
|
||||||
|
.lpstrFile = file,
|
||||||
|
.nMaxFile = MAX_PATH,
|
||||||
|
.lpstrTitle = L"Select File to Write To",
|
||||||
|
.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST
|
||||||
|
};
|
||||||
|
|
||||||
|
int res = GetOpenFileNameW(&ofn);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
_putws(L"File selection cancelled or failed!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *f = _wfopen(ofn.lpstrFile, L"w");
|
||||||
|
if (!f) {
|
||||||
|
_wperror(L"Error opening file for writing");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fwprintf(f, L"foo") < 0) {
|
||||||
|
_wperror(L"Error writing to file");
|
||||||
|
fclose(f);
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
wprintf(L"Successfully wrote \"foo\" to '%s'.\n", ofn.lpstrFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <shobjidl.h> // Required for IFileDialog and related interfaces
|
#include <shobjidl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
82
programs/source/IFileSaveDialog.c
Normal file
82
programs/source/IFileSaveDialog.c
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <shobjidl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
fprintf(stderr, "CoInitializeEx failed: 0x%lx\n", hr);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char file[MAX_PATH] = {0};
|
||||||
|
IFileSaveDialog *pFileSave = NULL;
|
||||||
|
IShellItem *pItem = NULL;
|
||||||
|
PWSTR pszFilePath = NULL;
|
||||||
|
|
||||||
|
hr = CoCreateInstance(&CLSID_FileSaveDialog, NULL, CLSCTX_ALL,
|
||||||
|
&IID_IFileSaveDialog, (void**)&pFileSave);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
COMDLG_FILTERSPEC rgSpec[] = {{L"All Files", L"*.*"}};
|
||||||
|
pFileSave->lpVtbl->SetFileTypes(pFileSave, ARRAYSIZE(rgSpec), rgSpec);
|
||||||
|
|
||||||
|
pFileSave->lpVtbl->SetTitle(pFileSave, L"Save File As");
|
||||||
|
|
||||||
|
DWORD dwFlags;
|
||||||
|
pFileSave->lpVtbl->GetOptions(pFileSave, &dwFlags);
|
||||||
|
pFileSave->lpVtbl->SetOptions(pFileSave, dwFlags | FOS_OVERWRITEPROMPT | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR);
|
||||||
|
|
||||||
|
hr = pFileSave->lpVtbl->Show(pFileSave, NULL);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
printf("GetResult...\n");
|
||||||
|
hr = pFileSave->lpVtbl->GetResult(pFileSave, &pItem);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
printf("GetDisplayName...\n");
|
||||||
|
hr = pItem->lpVtbl->GetDisplayName(pItem, SIGDN_FILESYSPATH, &pszFilePath);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
wcstombs(file, pszFilePath, MAX_PATH);
|
||||||
|
printf("Selected file: %s\n", file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pszFilePath) {
|
||||||
|
CoTaskMemFree(pszFilePath);
|
||||||
|
}
|
||||||
|
if (pItem) {
|
||||||
|
pItem->lpVtbl->Release(pItem);
|
||||||
|
}
|
||||||
|
if (pFileSave) {
|
||||||
|
pFileSave->lpVtbl->Release(pFileSave);
|
||||||
|
}
|
||||||
|
CoUninitialize();
|
||||||
|
|
||||||
|
if (FAILED(hr) || file[0] == '\0') {
|
||||||
|
puts("File selection cancelled or failed.");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *f = fopen(file, "w");
|
||||||
|
if (!f) {
|
||||||
|
perror("Error opening file for writing");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fprintf(f, "foo") < 0) {
|
||||||
|
perror("Error writing to file");
|
||||||
|
fclose(f);
|
||||||
|
exit(1);
|
||||||
|
} else {
|
||||||
|
puts("Successfully wrote \"foo\" to the file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
34
programs/source/QT_getSaveFileName.cpp
Normal file
34
programs/source/QT_getSaveFileName.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include <QApplication>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
QString fileName = QFileDialog::getSaveFileName(nullptr, "Select File", "", "All Files (*.*)");
|
||||||
|
|
||||||
|
if (fileName.isEmpty()) {
|
||||||
|
qDebug() << "File selection cancelled.";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(fileName);
|
||||||
|
|
||||||
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
std::cerr << "Failed to open file for writing: " << file.errorString().toStdString() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream out(&file);
|
||||||
|
|
||||||
|
out << "foo";
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
qDebug() << "Successfully wrote \"foo\" to:" << fileName;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
5
programs/source/QT_getSaveFileName.pro
Normal file
5
programs/source/QT_getSaveFileName.pro
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
QT += core widgets
|
||||||
|
CONFIG += console
|
||||||
|
SOURCES += QT_getSaveFileName.cpp
|
||||||
|
TARGET = QT_getSaveFileName
|
||||||
|
DESTDIR = compiled
|
31
programs/source/QT_getSaveFileUrl.cpp
Normal file
31
programs/source/QT_getSaveFileUrl.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include <QApplication>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <iostream>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
QUrl url = QFileDialog::getSaveFileUrl(nullptr, "Select File", QUrl(), "All Files (*.*)");
|
||||||
|
if (!url.isValid() || !url.isLocalFile()) {
|
||||||
|
qDebug() << "File selection cancelled.";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(url.toLocalFile());
|
||||||
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
std::cerr << "Failed to open file for writing: " << file.errorString().toStdString() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream out(&file);
|
||||||
|
out << "foo";
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
qDebug() << "Successfully wrote \"foo\" to:" << url.toLocalFile();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
5
programs/source/QT_getSaveFileUrl.pro
Normal file
5
programs/source/QT_getSaveFileUrl.pro
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
QT += core widgets
|
||||||
|
CONFIG += console
|
||||||
|
SOURCES += QT_getSaveFileUrl.cpp
|
||||||
|
TARGET = QT_getSaveFileUrl
|
||||||
|
DESTDIR = compiled
|
Loading…
x
Reference in New Issue
Block a user