ViRb3 / PerfectProxyDLL

A simple and stable proxy DLL for Windows x64
10 stars 1 forks source link

32-bit support #3

Open ViRb3 opened 2 years ago

ViRb3 commented 2 years ago

Any idea how to get this work under 32-bit environment ? I can compile the the project without issues, but any application I launch where this library gets initialized crashes with access violation after I confirm the message box

Originally posted by @iceman-77 in https://github.com/ViRb3/PerfectProxyDLL/issues/2#issuecomment-1058591039

ViRb3 commented 2 years ago

I have not tested this project for 32-bit compilation. It should definitely work, but some changes may be necessary.

iceman-77 commented 2 years ago

I tried to get it working the whole day today, I found that the exports for the 32-bit version.dll are missing the GetFileVersionInfoExA and GetFileVersionInfoSizeExA. So some code modification is definitely needed here. Also, for 32-bit to compile the declspec function needs to be modified as asm("jmp *_orig_"#name). Despite these changes any program that loads this DLL crashes with access violation. I was trying to catch the crash via ASM debugger, but no luck so far. Any help here would be greatly appreciated

ViRb3 commented 2 years ago

I'd recommend debugging with x64dbg, it will definitely allow you to catch the issue.

iceman-77 commented 2 years ago

I am using IDA Pro Advanced. It does not crash within the library, nor as a result of calling the redirected Exports. I am suspecting perhaps my compiler is causing issues. Is there any specific version, specific flavor you would suggest ?

iceman-77 commented 2 years ago

OK, I did some debugging and I found the problem. Your asm directive instructs to jump to the original function. The compiler however generates some extra opcodes that messes up the stack, especially the return address of the calling routine:

.text:65981428                 public __GetFileVersionInfoExW
.text:65981428 __GetFileVersionInfoExW proc near
.text:65981428                 push    ebp             ; <= this directive messes up the stack
.text:65981429                 mov     ebp, esp
.text:6598142B                 jmp     ds:_orig_GetFileVersionInfoExW
.text:6598142B __GetFileVersionInfoExW endp
.text:6598142B
.text:6598142B ; ---------------------------------------------------------------------------
.text:65981431                 align 2
.text:65981432                 pop     ebp
.text:65981433                 retn

The EBP register is zero at addr 0x65981428 , if it gets pushed to stack, this becomes the return address for the _orig_GetFileVersionExW. Once the original routine finishes, it instructs to "return" to the address that has been pushed by EBP register. That address is 0, hence the access violation crash.

I am yet to figure out how to prevent the compiler to generate those push and mov directives. If you have any ideas, let me know

iceman-77 commented 2 years ago

I fixed it as follows:

#define WRAPPER_GENFUNC(name) \
    FARPROC orig_##name; \
    __declspec(naked) void _##name() \
    { \
        asm("pop %ebp; jmp *_orig_"#name); \
    }

Not the most elegant way but it works. it produces the following assembly code:

.text:65981438                 public __GetFileVersionInfoA
.text:65981438 __GetFileVersionInfoA proc near
.text:65981438                 push    ebp
.text:65981439                 mov     ebp, esp
.text:6598143B                 pop     ebp             ; <= this instuction negates the "push ebp" created by the compiler
.text:6598143C                 jmp     ds:_orig_GetFileVersionInfoA
.text:6598143C __GetFileVersionInfoA endp
.text:6598143C

Perhaps there is a more elegant way to do it, maybe its just a code optimization settings in the compiler. If you figure it out, let me know. As a temporary solution, the above would work