Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to pass arguments to main payload in run-PE (or any program written by libPeConv)? #56

Open
mhscXXl opened this issue Jan 25, 2024 · 1 comment

Comments

@mhscXXl
Copy link

mhscXXl commented Jan 25, 2024

Issue:
I have tried to pass arguments to a payload loaded by libpeconv but it wasn't possible directly. So i decided to go a little bit deeper and modified some stack related parts of the code, it was successful but this method is heavily relied on Non-standard methods and requires more or less complicated modifications on the main code.

Is there any possible ongoing features that are not yet published or any other methods that i could use for this matter?

@kem0x
Copy link

kem0x commented Aug 30, 2024

I've looked into this, you can't simply do EntryPoint(argc, argv), This happens due to the fact that normal PEs entry point is not actually int main(...) but rather int64_t crt_main() which is responsible of calling and _p___argc and __p___argv or __p___wargv and passing them to the real main function after setting up the CRT. seems like there is no straightforward way to approach this but the solution i went with was hooking the real main

here's a quick demo:

constexpr inline ptrdiff_t RealMainOffset = ...;

inline peconv::PatchBackup PayloadMainBackup;

const wchar_t* NewArgv[] = { L"....exe", L"--version" };
constexpr auto NewArgc = sizeof(NewArgv) / sizeof(NewArgv[0]);

inline auto RealEntryPoint = (int(*)(int , const wchar_t** , const char**))nullptr;

static int PayloadMainHook(int argc, const wchar_t** argv, const char** envp)
{
    PayloadMainBackup.applyBackup();

    argc = NewArgc;
    argv = NewArgv;

    return RealEntryPoint(argc, argv, envp);
}

int main()
{
    // Load the PE normally
   
    // ...

    auto EntryPointOffset = peconv::get_entry_point_rva((BYTE*)PayloadModuleBase);

    RealEntryPoint = (decltype(RealEntryPoint))(PayloadModuleBase + RealMainOffset);

    peconv::redirect_to_local(RealEntryPoint, &PayloadMainHook, &PayloadMainBackup);

    auto EntryPoint = (int(*)())(PayloadModuleBase + EntryPointOffset);

    return EntryPoint();
}

This for sure isn't convenient for a library, The way the library can approach this imo is doing some simple dynamic analysis on the crt main to find the real main and hook it, i think this is the best way instead of editing the args pushed to the host process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants