1

I'm trying to get information about menu items in an application. Experimentally established that InsertMenuItemW is called. Thanks to the documentation, I set the number of input parameters and wrote this hook.

var InsertMenuItemW = Module.findExportByName("user32.dll", "InsertMenuItemW");
const oInsertMenuItemW = new NativeFunction(InsertMenuItemW, 'pointer', ['pointer', 'pointer', 'pointer', 'pointer']);
Interceptor.replace(oInsertMenuItemW, new NativeCallback((pathPtr, pathPtr1, pathPtr2, pathPtr3) => {
    console.log(" "+pathPtr, pathPtr1, pathPtr2, pathPtr3);
    const fd = oInsertMenuItemW(pathPtr, pathPtr1, pathPtr2, pathPtr3);
    return fd;
}, 'pointer', ['pointer', 'pointer', 'pointer', 'pointer']));

According to the documentation, I can get information about the new menu item by calling MENUITEMINFOA. But I can't figure out how to do it with Frida.

https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-insertmenuitemw

Question update

I was advised in the comments to use Memory.alloc.

On the Internet, I found this example where the hook allows you to read downloaded files.

var pGetFileInformationByHandleEx = Module.findExportByName("kernel32.dll", "GetFileInformationByHandleEx");

var fGetFileInformationByHandleEx = new NativeFunction(pGetFileInformationByHandleEx, "bool",["pointer", "uint", "pointer", "uint"]);

function getNameFromHandle(hFile) {
    var lpFileInformation = Memory.alloc(0x200);
    // 0x2 -> FILE_NAME_INFO
    var callRes = fGetFileInformationByHandleEx(hFile, 0x2, lpFileInformation, 0x200);
    if (callRes) {
        console.log("|_ hFile: " + (lpFileInformation.add(0x4)).readUtf16String());
    } else {
        console.log("|_ hFile: N/A");
    }
}

According to the documentation the third parameter (output).

BOOL GetFileInformationByHandleEx(
  [in]  HANDLE                    hFile,
  [in]  FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
  [out] LPVOID                    lpFileInformation,
  [in]  DWORD                     dwBufferSize
);

in the code you can see that we are passing the third parameter:Memory.alloc(0x200);

var callRes = fGetFileInformationByHandleEx(hFile, 0x2, lpFileInformation, 0x200)

But according to the InsertMenuItem documentation the fourth parameter is [in, out]

BOOL GetMenuItemInfoA(
  [in]      HMENU           hmenu,
  [in]      UINT            item,
  [in]      BOOL            fByPosition,
  [in, out] LPMENUITEMINFOA lpmii
);

As I understand it, we must pass the lpmi of our InsertMenuItem as the fourth parameter. But how do we get out?

My current code

var InsertMenuItemW = Module.findExportByName("user32.dll", "InsertMenuItemW");
var GetMenuItemInfoW = Module.findExportByName("user32.dll", "GetMenuItemInfoW");


var fGetMenuItemInfoW = new NativeFunction(GetMenuItemInfoW, "bool",["pointer", "pointer", "pointer", "pointer"]);
function getHandle(hmenu, item, fByPosition, lpmi) {
    var lpFileInformation = lpmi || Memory.alloc(0x200);
    var lpFileInformation2 = Memory.alloc(0x200);
    var callRes = fGetMenuItemInfoW(hmenu, item, fByPosition, lpmi);
    console.log(lpFileInformation2);
    console.log("-----------");
}
const oInsertMenuItemW = new NativeFunction(InsertMenuItemW, 'pointer', ['pointer', 'pointer', 'pointer', 'pointer']);
Interceptor.replace(oInsertMenuItemW, new NativeCallback((hmenu, item, fByPosition, lpmi) => {
    
    //call GetMenuItemInfoW
    getHandle(hmenu, item, fByPosition, lpmi);
    const fd = oInsertMenuItemW(hmenu, item, fByPosition, lpmi);
    return fd;
}, 'pointer', ['pointer', 'pointer', 'pointer', 'pointer']));
6
  • I would start by importing InsertMenuItemW the same way you imported InsertMenuItemW. For the out parameter you will have to allocate memory using Memory.alloc.
    – Robert
    Apr 12 at 17:07
  • Thanks for the answer. Can you explain why I need to use GetMenuItemInfoA and not GetMenuItemInfoW ?
    – user123
    Apr 13 at 5:21
  • It doesn't matter which version you use. Unless your system language uses multi-byte characters you don't need to use the W version. Usually handling of Wide strings (UTF-16) is often more complicated. Not sure about Frida if wide strings are well supported.
    – Robert
    Apr 13 at 6:59
  • @Robert doesn't it still matter whether the applications against which you use it uses the A or the W variety? I don't quite get your reasoning here. Unless you hook the underlying functionality from win32u.dll (previously user32.dll) these would be different code paths. Also note: ECMAscript uses UTF-32 internally, so I'd expect UTF-16 to be no issue.
    – 0xC0000022L
    Apr 13 at 7:55
  • From the documentation, it's not entirely clear to me how to get out. The documentation says that the fourth parameter is both input and output. I found an example on the Internet but it does not quite fit this case. Updated the question.
    – user123
    Apr 13 at 8:37

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.