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

Fixing support for inject_x64 injection inside WOW64 processes #4989

Merged
merged 23 commits into from
Jul 13, 2021
Merged

Fixing support for inject_x64 injection inside WOW64 processes #4989

merged 23 commits into from
Jul 13, 2021

Conversation

N0fix
Copy link
Contributor

@N0fix N0fix commented Jul 1, 2021

PR for issue#4990.

Those changes fixes support for inject_x64 injection on WoW64 processes, which allows support for mixed mode code, see this

Note that allocation of vmheap fails upon initializing dynamoRIO 64 on WoW64 processes. Thus, we need to pass -reachable_heap to avoid having to make this allocation.

We still need to have a proper support on drrun64 to inject natively without having to use create_process.exe.

Example command line that works :

bin64\drrun.exe -reachable_heap -inject_x64 -c .\clientdll.dll -- bin64\create_process.exe .\helloworld32.exe

As we need to specify reachable_heap I am afraid that win32.mixedmode test will be needing some tweaks.

Changes features :

  • Saving eax register that holds routine address for RtlUserThreadStart before mode switch, and restore it on mode switch
  • Fixing far jmp to switch to x64 mode on injection
  • Fixing env variable argument propagation

EDIT

-reachable_heap should not be required anymore since vmheap injection issues has been fixed in this commit.

@N0fix N0fix changed the title [PR] Fixing support for inject_x64 injection inside WOW64 processes Fixing support for inject_x64 injection inside WOW64 processes Jul 1, 2021
Copy link
Contributor

@derekbruening derekbruening left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this and contributing the patch. I'm not sure I understand some of it though.

core/win32/inject.c Outdated Show resolved Hide resolved
core/win32/inject.c Outdated Show resolved Hide resolved
core/win32/inject.c Outdated Show resolved Hide resolved
// commenting this ASSERT since x64 client injected in
// WOW64 binaries will be using mc->rax as comparaison
// thus making the assert fail, while the syscall still
// being valid.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A) Who is setting the upper bits?

B) You mean the Windows kernel ignores the upper bits? So the assert is flawed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant that the assert always fails due to the size of mc->rax being compared with wrong sizes, no matter if the syscall is valid or not.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand "the assert always fails due to the size of mc->rax being compared with wrong sizes"?

Copy link
Contributor Author

@N0fix N0fix Jul 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to print the first erroneous syscall (syscall that makes the assert trigger) on WoW64 + inject_x64, I can see that mc->xax value is ffffffff00031054. I assume that this comes from a conversion somehow representing the syscall with a signed number, which outputs a value that is wrong if you display it. Since mc->xax is only used as a sysnumber and type converted to int, this is not an issue, but this still makes ASSERT_TRUNCATE (more precisely CHECK_TRUNCATE_TYPE_int) fail.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There would not be a widening conversion for an application register. App register values have to be precisely preserved. The machine context structure stores 64-bit values and prints them as such. If the top bits there are 1's, either the app set them to 1's, or somehow there is a bug where DR corrupted the register value. Is this for 32-bit app code? If it is 64-bit, we can't put it past Windows making some change to have the top bits mean something -- though in the past 64-bit code wrote to eax, zeroing the top bits.

@@ -1744,7 +1744,10 @@ propagate_options_via_env_vars(dcontext_t *dcontext, HANDLE process_handle,
* model without requiring setting up config files for children.
*/
uint64 peb;
bool peb_is_32 = is_32bit_process(process_handle);
bool peb_is_32 = is_32bit_process(process_handle)
// if x64 client targeting WOW64 we need to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Modern style is to prefer capitalized and punctuated whole-sentence comments.

core/heap.c Outdated Show resolved Hide resolved
core/optionsx.h Show resolved Hide resolved
core/win32/inject.c Show resolved Hide resolved
@derekbruening
Copy link
Contributor

All the tests are failing: looks like b/c of tabs:

ERROR: diff contains tabs:
  +	 // if x64 client targeting WOW64 we need to

The style convention is to not have any tabs.

@derekbruening
Copy link
Contributor

Tests are all still failing with clang-format style violations:

 ERROR: diff contains trailing spaces:
  + // XXX : We should also be testing for target to be wow64 along with

-- Changes are not formatted properly:

@N0fix
Copy link
Contributor Author

N0fix commented Jul 9, 2021

Tests are all still failing with clang-format style violations:

 ERROR: diff contains trailing spaces:
  + // XXX : We should also be testing for target to be wow64 along with

-- Changes are not formatted properly:

Fixed in last commit

@derekbruening
Copy link
Contributor

There are more -- I would suggest checking the entire diff, or better following the development setup make/git/devsetup.sh https://dynamorio.org/page_workflow.html#autotoc_md296 which checks for trailing spaces and other things at local commit time.

  ERROR: diff contains trailing spaces:
  + // If x64 client targeting WOW64 we need to

There are also clang-format failures -- see the ci-clang-format test. I would suggest setting up clang-format in your editor.

@N0fix
Copy link
Contributor Author

N0fix commented Jul 9, 2021

There are more -- I would suggest checking the entire diff, or better following the development setup make/git/devsetup.sh https://dynamorio.org/page_workflow.html#autotoc_md296 which checks for trailing spaces and other things at local commit time.

  ERROR: diff contains trailing spaces:
  + // If x64 client targeting WOW64 we need to

There are also clang-format failures -- see the ci-clang-format test. I would suggest setting up clang-format in your editor.

Just removed other trailing spaces.
I was looking for your dev setup, thanks for the links, I will take a look into it if this merge fails.

core/heap.c Outdated Show resolved Hide resolved
core/win32/syscall.c Outdated Show resolved Hide resolved
@N0fix
Copy link
Contributor Author

N0fix commented Jul 13, 2021

Not sure about what is failing in Windows build. Looks like a CI error that is not coming from my code.

@derekbruening
Copy link
Contributor

Not sure about what is failing in Windows build. Looks like a CI error that is not coming from my code.

I think it's a sourceforge server error causing doxygen to not get downloaded. Probably re-running is the first thing to try: I clicked re-run.

@derekbruening
Copy link
Contributor

run arm tests

@derekbruening
Copy link
Contributor

@AssadHashmi -- is there any way to enable existing contributors to trigger AArch64 Jenkins runs from a forked PR? It seems there's no way to do that now for a PR from a forked PR created by a new contributor.

@derekbruening
Copy link
Contributor

Going to merge this w/o the Jenkins for now: the master run will catch issues. Cross-compile for these code changes gives high confidence. Once @AssadHashmi is back we'll try to figure out a better long term solution.

@derekbruening derekbruening merged commit 89841a1 into DynamoRIO:master Jul 13, 2021
sapostolakis pushed a commit that referenced this pull request Jul 14, 2021
Fixes issues around the -inject_x64 prototype option added by PR #4653 for #803 to enable injecting a 64-bit DR into a WOW64 (32-bit) child ("mixed mode").

Xref discussion at https://groups.google.com/g/dynamorio-users/c/rhEpslerwf8

Adds a new option -vmheap_size_wow64 since the default x64 size will not fit in a WOW64 process.
Saves eax register that holds routine address for RtlUserThreadStart before mode switch, and restores it on mode switch.
Fixes far jmp to switch to x64 mode on injection.
Fixes env variable argument propagation.

Example command line that works :

  $ bin64\drrun.exe -inject_x64 -c .\clientdll.dll -- bin64\create_process.exe .\helloworld32.exe

We still need to add proper support on drrun64 to inject natively without having to use create_process.exe.

Issue: #49, #4990
@AssadHashmi
Copy link
Contributor

add to whitelist

@AssadHashmi
Copy link
Contributor

ok to test

@AssadHashmi
Copy link
Contributor

test this please

@derekbruening
Copy link
Contributor

run arm tests

@derekbruening
Copy link
Contributor

I think once it's merged nothing will run

@AssadHashmi
Copy link
Contributor

I think once it's merged nothing will run

You're right @derekbruening.
add to whitelist worked for a new contributor @mat-kalinowski on his first PR #5020 (comment)

@N0fix
Copy link
Contributor Author

N0fix commented Jul 29, 2021

An encoding cti error is occurring inside generate_switch_mode_jmp_to_hook on latest builds (from source or cronbuild, doesn't matter), upon injecting into x86 binaries. I have been looking at commits since this PR, and I did not find something that would have interfere with this PR at first glance.

EDIT

This can be fixed changing this to :

 bool target_64 = !x86_code IF_X64(|| !DYNAMO_OPTION(inject_x64));

But this seems to create syscall issues later on on my current Win10 OS. Upon creating a message box (target app calls MessageBoxA), DynamoRIO crashes with : Usage error: Is your client invoking raw system calls via vdso sysenter? While such behavior is not recommended and can create problems, it may work with the -sysenter_is_int80 runtime option.

Windows 10 Build 19041

@N0fix
Copy link
Contributor Author

N0fix commented Jul 29, 2021

I can confirm that mixed code injection is not working anymore on latest cronbuilds (18324 and 18331, since PR basically).

I have a working version of dynamoRIO with injection somewhere. I have been testing this PR again, and the error occurs. So the problem comes from my side, I might have forgotten some change I have made somewhere. I will check that soon and submit a PR fixing that.

@derekbruening
Copy link
Contributor

A regression test should be enabled to avoid breakage.

@N0fix
Copy link
Contributor Author

N0fix commented Jul 30, 2021

A regression test should be enabled to avoid breakage.

Applying modification from this PR to #4653 (#803) works perfectly well, if we add :

			if (is_32bit_process(phandle) && DYNAMO_OPTION(inject_x64)) {
				target_64 = false;
			}

that I did forget in my PR.

The syscall trouble must be coming from some other commit since this PR. Would you know which commit might have mess with syscall handling since then?

@N0fix
Copy link
Contributor Author

N0fix commented Jul 30, 2021

Trouble starts from cronbuild-8.0.18663, we need to check commits between 18655 and 18663.

N0fix added a commit to N0fix/dynamorio that referenced this pull request Aug 2, 2021
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

Successfully merging this pull request may close these issues.

3 participants