News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

Entering the Heaven's Gate with FLAT:1

Started by aw27, June 07, 2019, 01:16:56 AM

Previous topic - Next topic

aw27

Heaven's Gate: 64-bit code in 32-bit file
Closing "Heaven's Gate"

This is a fast essay to test the OPTION FLAT:1. We enter the Heaven's Gate, collect a value from the RCX register, split in 2 registers to return to 32-bit, and print it in the 32-bit World.

Hello from 32 bit. RCX sent you this from x64: 0x12345678abcdef


Note: It has bugs, but works  :skrewy:



aw27

This is a reviewed version. The other one is messy and not even I could explain correctly why it worked.
Now is clear like water.


LiaoMi

 :biggrin:



In the last topic, almost all variations work. I thought that if I debugged one option, I could debug the second one. This was a mistake, in Windbg it is possible to debug with the transition to different states, it will be interesting to try the new debugger, see how replay works  :azn:

2B||!2B

Nice example there AW.

The mixing is a good idea. However, it comes with some limitations like one can not load modules that depend on other modules like kernel32 64bit. It works only if your module depends on Ntdll only.
When it comes to debugging, WinDbg x64 is the only debugger as i know of that is capable of switching between 32bit and 64bit on the fly.

aw27

Thank you, LiaoMi - Your investigations are always very useful!  :thumbsup:

@2B||!2B
It is indeed difficult to navigate in these waters. Some of the barriers are welcome, though, to put a frein on malware.

An interesting problem I faced is that it is not possible, or I could not figure out how, to write to the .data section from the 64-bit code. In other words, it points correctly to the variable but produces an exception when writing. Are writing permissions for 64-bit different from 32-bit on PE sections? Any idea? 

jj2007

Any idea why this...
to64bitWorld proc
mov     edi,dword ptr [rsp]
int 3
jmp     fword ptr [rdx]    ; <<<<<<<<<<<<<<<<<<<<


... ends up here?
RtlUserThreadStart  Ú$  894424 04                   mov [esp+4], eax
776401E8            ³.  895C24 08                   mov [esp+8], ebx
776401EC            À. E9 C9950200                 jmp 776697BA


In case somebody has way too much free time: read this :cool:

aw27

Quote from: jj2007 on June 07, 2019, 05:10:54 PM
Any idea why this...
to64bitWorld proc
mov     edi,dword ptr [rsp]
int 3
jmp     fword ptr [rdx]    ; <<<<<<<<<<<<<<<<<<<<


... ends up here?
RtlUserThreadStart  Ú$  894424 04                   mov [esp+4], eax
776401E8            ³.  895C24 08                   mov [esp+8], ebx
776401EC            À. E9 C9950200                 jmp 776697BA


I end up here:
0040105f 8b3c24          mov     edi,dword ptr [esp]
00401062 cc              int     3
00401063 ff2a            jmp     fword ptr [edx]

But is a good point, because in there we are still in 32-bit. The procedure should be changed to (removing the USE64 from where it was):

to64bitWorld proc
mov     edi,dword ptr [esp]
USE64
jmp     fword ptr [rdx]
offjump::
mov rcx, 012345678ABCDEFh
mov rax, rcx
mov rdx, rcx
shr rdx, 32

; Return to 32-bit World
mov     dword ptr [rsp+4],23h
mov     dword ptr [rsp],edi
jmp     fword ptr [rsp]
to64bitWorld endp


Does it make any difference in your debugger?

jj2007

Quote from: AW on June 07, 2019, 05:29:07 PMDoes it make any difference in your debugger?

Yes, it chokes and shows only garbage:0040105C            Ú$  CC                          int3
0040105D            ³.  67:8B3C                     mov edi, [si]
00401060            ³.  24 FF                       and al, FF
00401062            ³.  2A48 B9                     sub cl, [eax-47]
00401065            ³.  EF                          out dx, eax
00401066            ³.  CD AB                       int 0AB
00401068            ³. 78 56                       js short 004010C0


How does WinDbg behave?

aw27

Quote from: jj2007 on June 07, 2019, 05:34:11 PM
How does WinDbg behave?

Windbg does not go astray but reports the next instruction as "jmp     fword ptr [edx]" and it is right. We are still in 32-bit there, only on the next instruction we enter 64-bit..
So, does it help if you change to? :

to64bitWorld proc
mov     edi,dword ptr [esp]
jmp     fword ptr [edx]
USE64
offjump::
.....

2B||!2B

Try these macros to enter/leave 64bit mode. It is similar to wow64cpu!X86SwitchTo64BitMode/wow64cpu!CpuSimulate

X64_Start macro
PUSH CS
CALL $+5
ADD [ESP],5
RETF   
endm

X64_End MACRO
    LOCAL  xx, rt
    call   $+5
    xx  equ $
    mov    dword ptr [rsp + 4], 23h
    add    dword ptr [rsp], rt - xx
    retf
    rt:
ENDM



Problem is, i can not test since i am on a 32bit machine and VMWare stopped working all of a sudden.

Quote from: AW on June 07, 2019, 05:02:25 PM
An interesting problem I faced is that it is not possible, or I could not figure out how, to write to the .data section from the 64-bit code. In other words, it points correctly to the variable but produces an exception when writing. Are writing permissions for 64-bit different from 32-bit on PE sections? Any idea?

Maybe you faced the same issue i faced there in my topic where the warnings of BSS in BIN that is caused by _flat section does not have writeable characteristics. It will take the place of .data section.

aw27

Quote from: 2B||!2B on June 07, 2019, 06:21:45 PM
Maybe you faced the same issue i faced there in my topic where the warnings of BSS in BIN that is caused by _flat section does not have writeable characteristics. It will take the place of .data section.

The BSS issue will probably be solved if you initialize to 0 instead of putting a question mark. But I don't know if it will work after that or if it is a bug (it sound like that).

jj2007

Quote from: AW on June 07, 2019, 05:41:34 PMSo, does it help if you change to?

to64bitWorld proc
mov     edi,dword ptr [esp]
jmp     fword ptr [edx]
USE64
offjump::


No change, disassembly looks ok, and stepping with F7 through the jmp brings you straight to RtlUserThreadStart. Which is the part that I don't yet understand: Does the transition trigger an interrupt that brings you there, or is it the debugger (Olly) that opens a thread for some reason? Same behaviour with X32Dbg. That's why I asked how WinDbg behaves.

aw27

@JJ,
Within WinDbg I can single step from x86 to x64. It will not go astray. I tested with x32dbg and there are problems.

@Attention Johsa and Habran:
In the attached new release, I found 2 "possible" bugs which I mention in the comments:
Possible Bug 1 -
mov    rcx, ‭012345678ABCDEFh  now produces "Error A2167: Missing quotation mark in string"
Possible Bug 2 -
Some Function Prototypes cause error if placed on top, but work if placed after USE32 clause

Other than the "possible" bugs, this new release transfers data from x64 to x86 through a memory mapped file. Now, no need to transport values in registers as we did previously (given that we can not transfer them through the heap - i.e .data section, this is a great step forward).

aw27

Another bug, possibly directly related to the use of ESP based stack frames.

If I change main like this:

main proc C
LOCAL hMapFile : ptr
invoke CreateFileMappingA, -1, 0, 4, 0, sizeof TBUFFMAP, 0
mov hMapFile, eax
invoke MapViewOfFile, hMapFile, 0f001fh, 0,0,sizeof TBUFFMAP ; <--- Will fail
mov esi, eax
call heavensGate

invoke printf, offset msg32, [esi+4], [esi]
invoke CloseHandle, hMapFile ; <--- Already fails
invoke ExitProcess,0
main endp


Fails happened because we are pushing parameters pointed to by the ESP based stack frame, so they change position after the push. Please have a look with a debugger, if not clear.


LiaoMi

#14
Quote from: jj2007 on June 07, 2019, 07:59:58 PM
Quote from: AW on June 07, 2019, 05:41:34 PMSo, does it help if you change to?

to64bitWorld proc
mov     edi,dword ptr [esp]
jmp     fword ptr [edx]
USE64
offjump::


No change, disassembly looks ok, and stepping with F7 through the jmp brings you straight to RtlUserThreadStart. Which is the part that I don't yet understand: Does the transition trigger an interrupt that brings you there, or is it the debugger (Olly) that opens a thread for some reason? Same behaviour with X32Dbg. That's why I asked how WinDbg behaves.

Hi jj2007,

Most user-mode debuggers indeed don't handle that transition well for multiple reasons (one being the debugger assumes a 32bit process, while you're now executing 64bit code, another being user-mode debugging APIs don't support that).

TL;DR: The "solution" for that situation is to debug using a debugger that explicitly made the effort to support 32 and 64 bit interleaved processes. Although this is often easier for a kernel mode debugger), such as windbg, or other debuggers that support both 32 and 64 bit modes (x64dbg should be able to do it, although I never tried As mentioned in the comments x64dbg is unable to do that).


I can only debug specially-crafted code, I don't know the dependency, even in this case, only 32 bit code is displayed, not 64 bit.
my mistake, debugger always points in ...

CMP     DWORD PTR DS:[7755E968], 0
JE      ntdll.774B41F7
MOV     ECX, DWORD PTR DS:[7755E968]
CALL    DWORD PTR DS:[<&RtlDebugPrintTimes>]
JMP     ECX
MOV     DWORD PTR SS:[ESP + 4], EAX