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

x64dbg two fatal bug #1960

Open
number201724 opened this Issue Jun 7, 2018 · 11 comments

Comments

Projects
None yet
4 participants
@number201724

number201724 commented Jun 7, 2018

Bug 1:
If the EXE EntryPoint is 0, Entry Breakpoint breaks to the PE Header's IMAGE_DOS_SIGNATURE

Bug2:
If you use ZwMapViewOfSection to load 2 copies of ntdll.dll (path is consistent) then the breakpoint on this module will be wrong. ZwOpenFile -> ZwCreateSection -> ZwMapViewOfSection

@number201724

This comment has been minimized.

number201724 commented Jun 7, 2018

Some programs use TLS CALLBACK to start.

@mrexodia

This comment has been minimized.

Member

mrexodia commented Jun 8, 2018

Zero is a valid entry point. See https://corkamiwiki.github.io/PE

For bug 2, could you provide some clearer information? Example executable or steps perhaps.

@number201724

This comment has been minimized.

number201724 commented Jun 8, 2018

Yes 0 is a valid entry point, but the breakpoint of x64dbg is in the PE header instead of the code segment.

@number201724

This comment has been minimized.

number201724 commented Jun 8, 2018

Bug2 I will write a demo later

@abbasfull

This comment has been minimized.

abbasfull commented Jun 8, 2018

@number201724

This comment has been minimized.

number201724 commented Jun 13, 2018

@number201724

This comment has been minimized.

number201724 commented Jun 13, 2018

Example 1: When the entry breakpoint is turned on, he crashes in ntdll

@Mattiwatti

This comment has been minimized.

Contributor

Mattiwatti commented Jul 29, 2018

I don't really care about the 0 entry point thing, sorry.

I was more interested in the double mapped ntdll breakpoints misbehaving since a lot of protectors are remapping ntdll nowadays. So I rewrote your sample code a bit since I didn't understand the issue at first:
Code here
32/64 bit EXEs + PDBs

How to reproduce:

  • Run the sample exe and let it reach the EP, then set a BP on NtClose.
  • Press F9
  • The breakpoint will hit in the original ntdll.dll (e.g. at 0x076DA9990 for me).
  • Press F9
  • The same breakpoint will hit again, but at a completely different address, since the second call is to NtClose in the remapped DLL (e.g. 0x3B9990 for me).

Both calls will work since as far as the kernel is concerned there is no difference between a DLL and a SEC_IMAGE mapping. In fact, mapping a section image will cause the debugger to receive a LOAD_DLL_DEBUG_INFO event, which probably isn't helping. So how come Process Hacker is able to tell the difference?

PH

...By walking the ntdll loader entry list out-of-process. See PhpEnumProcessModules for the DLLs-only enumeration which is gross enough, and PhpEnumProcessModulesCallback for the truly sickening abomination that also includes mapped files and sections. Note that both of these functions are OS-dependent since the size and members of LDR_DATA_TABLE_ENTRY change with every Windows release.

I'm guessing the breakpoint identifiers are (at least partially) name-based (and/or with an RVA from the module) to prevent the breakpoints list from being wiped due to relocations? If so that makes sense and seems more important to me than fixing this.

The load order of an image is not very useful to distinguish between duplicate DLLs since this load order can be easily manipulated by the debuggee. The 'WinDbg way' is another not-so-hot option: WinDbg simply concatenates the base address to any duplicate module names. Of course, WinDbg doesn't actually bother saving breakpoints anyway...

I think, as a compromise, (since these 'double mapped' faux images are usually system DLL files) the \KnownDlls object directory could actually be quite useful. The DLLs contained in this directory are system DLLs that receive the same virtual address in all processes and are only subject to ASLR on the next reboot. smss.exe maps a global section view for each entry in \KnownDlls as part of the initial session initialization.

KnownDlls

So, it is trivial to determine for a given section mapping whether it (1) has a known DLL name, and if so, (2) whether it has the canonical address of the DLL by comparing it to the \KnownDlls section handle. We still can't store the DLL base itself as it will change on the next boot, but we can query and store the 'KnownDll-ness' (yes/no) property as part of the breakpoint ID, I think?

So possible proposal for at least fixing the POC behaviour:

  • Breakpoint 1, with say, ID { name = ntdll.NtClose } in the example would become breakpoint { name = ntdll.NtClose, KnownDll = true }
  • Breakpoint 2 with duplicate ID { name = ntdll.NtClose } would become { name = ntdll.NtClose, KnownDll = false }
    (I'm assuming symbol names for IDs here, but the same principle applies if the BP identifier is something like the DLL name plus the breakpoint RVA.)
@number201724

This comment has been minimized.

number201724 commented Jul 29, 2018

For 0 entry point, he should not set the breakpoint to the IMAGE_DOS_SIGNATURE of the PE header.

@number201724

This comment has been minimized.

number201724 commented Jul 29, 2018

This will cause the ntdll LdrXXXXX function to crash.

@Mattiwatti

This comment has been minimized.

Contributor

Mattiwatti commented Jul 29, 2018

Alright alright. Your first PE now runs for me with the above PR applied.

@x64dbg x64dbg deleted a comment from sakashittu Aug 18, 2018

@x64dbg x64dbg deleted a comment from sakashittu Aug 18, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment