-
Notifications
You must be signed in to change notification settings - Fork 218
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
Allow disabling optimization of return value for a function #6269
Comments
There's a few options already for this case I believe. First you can right click on the function and edit function properties and change the modified registers in cases where the analysis doesn't know a register is tainted. Secondly, I believe we were discussing but I don't know if it's implemented the ability to set the global variables type to volatile. The opposite is true and you can set a variable to be const in a writable section. However either way you can create a section over that variable using the memory map view and set it to read write data. Let me know if any of those work to solve your problem! Documentation that touches on this is in https://dev-docs.binary.ninja/dev/concepts.html#memory-permissions-impact-on-analysis but I see I need to fix some formatting errors. If volatile works I'll add some more detailed examples. |
In all 3 cases above, the relevant register is rax, which is already marked as clobbered in function properties by default since it is the return register. For the volatile/rw permissions, I don't think that would help here. The only global variable in the code above is from the 3rd case ( |
Thx for filing the issue! I am thinking of it and see what is the best solution. To start with, I think case 3) is probably not a bug -- not only our decompilation is semantically correct, I feel like it is also closer to the disassembly code. I have not seen the disassembly code yet, but I feel like it is going to be the same as what we showed. I could be wrong though -- if it is convenient for you, please share the binary with us (in public or private) so that we can take a closer look at it. |
For case 1), I think there are two possible ways to address the issue:
|
I agree it is semantically correct, but is not as clear as if the HLIL showed Current HLIL makes it seem like return value of
The disassembly calls Here is the binary:
To clarify, this would work by changing function signature from e.g. I think that would be a good solution, and would probably work to solve all 3 cases.
I think this could help for better default behaviour of vmmcall, but wouldn't help for the other 2 cases |
|
I am not quite sure I understand the second case -- is it possible to share the binary with us? |
Unfortunately I can't share that exact binary, but here is a binary I made that behaves similarly by using a signal handler. Note that in When an invalid address is passed to |
Thx for the binary! To start with, I would like to point out that this issue is NOT limited to return value optimization. I patched the code in I tested and found that setting the Update: setting |
I've found out that I can actually use UIDF to set the return variable of a function to UndeterminedValue to disable optimization of it. This works for the |
Yeah, sorry I'd didn't reply earlier: UIDF was going to be my suggestion as the best way to influence cases like that. The other would be to modify the arch to change the lifting of the instruction to an intrinsic that tainted the appropriate registers. |
What is the feature you'd like to have?
Sometimes binja thinks that a function has a constant return value, and will optimize any code that calls that function, assuming that the return value will always be that constant.
I would like to be able to disable this for specific functions since there are cases where binja mistakenly applies this optimization where it shouldn't.
Is your feature request related to a problem?
There are a few cases where this has been a problem.
The first example is for a function that uses the
vmmcall
instruction.The
vmmcall
will cause an exit to the hypervisor, which will modify the registers, then return (similar to a syscall).The call to
vmmcall_func
checks the return value of the vmmcall, and will go to an error path if it is non-zero.However, binja doesn't know that the vmmcall can modify the registers, and assumes that
eax
is always zero. So the error path code is completely optimized out in the HLIL:The second example is from a kernel that sets a fault handler then tries to read a user address. If a fault occurs, the fault handler is called which will return an error value. If no fault occurs, 0 is returned.
Again binja doesn't know that the eax register can change, so assumes this function always returns 0, and the error handling code in HLIL is optimized out.
The last example is less impactful, but I still find it a bit annoying.
Sometimes a function will simply return a global variable, and that value is used or passed to another function.
e.g.:
Binja will try to optimize the return value by using
my_global
directly, resulting in this HLIL:I think this results in more confusing code than if the return value wasn't optimized like that.
Are any alternative solutions acceptable?
For the vmmcall case, I think binja could have better default behaviour, but there will always be cases that binja can't handle, so it would be best to allow user to disable the optimization manually.
The text was updated successfully, but these errors were encountered: