sábado, 6 de agosto de 2011

QT 4 You

I was asked a couple months ago by a friend of mine to “tweak” a software protection as he wanted to “evaluate” more “thoroughly” the targeted program. As I went in to it, I found the protection scheme very interesting as it involved a couple of cross platforms based engines interacting together to serve as anti-hacking security licensing system. One was Qt, the other being JavaScript. It was the second time that I came against a Qt based software. The first time thought, I just used the basic cracking skills every reverser uses with Windows GDI apps. But this time I needed to go deeper to understand the cross VM interactions, and a bigger understanding of the Qt framework was needed, so, I engaged into searching for more info on the subject. The results were quite poor, except for an article by Daniel Pistelli, who now works at Hex Rays (coincidence that IDA has been reassembled using this framework?).

Besides his article, not much on the subject of reversing Qt code seemed to be around. Since then I was faced with a fair amount of Qt applications, even Portuguese ones, so I decided to post my thoughts on the subject, and build a tutorial for the 4th version of Qt (coincidentally its also the same version of IDA 6.1, hihi):

Note: The Qt platform has an OO approach, so consider before reading this tutorial, to gather some insight about reversing C++ stuff, like RTTI, MS calling convention, virtual functions, etc.

For the purpose of this demonstration I used a demo application who accompanies the Qt SDk called sdi.exe, located in the examples/mainwindows/sdi folder. You can use any program you wish, to follow this explanation, thought.

1. Recognizing the Entrypoint

Usually looks like this and Olly is smart enough to identify it as it is the EP defined in the PE header.

2. How to find Main?

Consider Main function source code. Let’s see what do we need to find it’s corresponding assembly code, and what this code looks like after compilation.

2.1. First step is to search for all inter-modular calls and locate the imported dispatcher function qWinMain defined in QtCore4.dll.

2.2 Second step, select QtCore4.qWinMain and jump into it’s code definition.

2.3. The first call after QtCore4.qWinMain sets up memory. But, we are impatient and we want QMain. QMain function will always be the second call, as highlighted in the figure.

To verify if we’ve selected the correct function call, go up some lines and the following api calls should be present:

- GetCommandLineW

- QString::fromWCharArray

- QString::toLocal8Bit

- QByteArray::detach

2.4. And we’re in QMain

2.5. The startup address is usually pointing to the start of the .CODE section

That is 401000 in this case.

3. Code analysis
3.1.
Instruction 1 – Initialize resources

If we enter the function, we should see the resources being pushed and the qRegisterResourceData function being called:

3.2 Instruction 2 – Instantiate QApplication

Pretty easy to follow right? The QApplication class is calling it’s constructor with the following arguments: Arg1 = argc, Arg2 = argv, Arg3 = compile_version

3.3.
Instruction 3


3.4. Instruction 4
3.5. Instruction 5

This function calls all the subclasses constructors

3.6. Instruction 6
3.7. Instruction 7
4. Intercept Messages in Qt

Messages in Qt are set thru slots definition. Slots are then connected using the connect macro to a QWidget based class. As sampled in the code:

So we have here 3 types of message redirection, the first one “saveAsAct” is defined in the slot set of the MainWindow class. “saveAsAct” will be made part of the MainWindow class dispatcher table.

The second one, “closeAct”, is defined as an overload of QMainWindow superclass, so it will not be part of MainWindow class dispatcher table, but will be dispatched thru MainWindow dispatcher function. But as “closeAct” is not found in MainWindow class dispatcher table it will be forwarded to QMainWindow superclass dispatcher using an Event class. The definition of “closeAct” is:

Finally “exitAct” is applied or connected to qApp. qApp is an instance of QApplication, so it can’t be intercepted in the MainWindow dispatcher function, but in QApplication dispatcher function.

Considering that everything was easy till now, this will be the “hard” part of the process, getting to trace the GDI interaction. Let’s see how we can accomplish this task. Basically there are three approaches that can be used:

4.1. Find and set a conditional breakpoint at QMetaObject::metacall with [esp+4] == object addr

The object is any GDI particular object like a QTextControl, QMainWindow, etc. that you might know it’s memory address.

4.2. Set a conditional breakpoint on Q<class of object>::qt_metacall with [esp+8] == WM_

4.3. Set a breakpoint on QMainWindow::qt_metacall (QMainWindow is defined in QtGui4.dll). This being a special case of the previous one.

On stop set a breakpoint on .code section of main executable, it should stop on the Qt dispatcher.

In the main Qt dispatcher built by the compiler, Olly tells us that there are 6 cases on switch.

The six destinations are set here:

Which correspond to the slots definitions of MainWindow class:

4.4. To target messages attached to events, set a breakpoint on QMainWindow::qt_metacall, on stop set a breakpoint on QMainWindow::event. After break set a new breakpoint in the .code section of main executable, it should stop on the Qt function you’re after.

For example, tracing the MainWindow::Close, after following the steps defined before we reach:


Just to confirm we’re in the right place let’s enter the first call:

Which is maybeSave() function who’s definition is:

See the corresponding text? We’re in the right place.

For the sake of completeness, there’s a caveat you need to be aware regarding the first approach I presented: Setting a breakpoint in QMetaObject::metacall. After entering QMetaObject::metacall and setting a breakpoint on the user section code of the main module, it won’t enter immediately in the function code we’re after; instead the metacall will just try to find the virtual stub function responsible for the dispatching. For resolving this, all you need is let the code enter in the Qt core dispatcher and then set a second section code breakpoint in the main module and finally you’ll be there.

Ufff… Good luck in you reversing.

Hope you enjoyed it!


PS: If you want the printed version of this text you can get it here.

quinta-feira, 14 de julho de 2011

Pointers for User Shared Data

Just a quick flash on how to find the kernel and user address of the Shared User Data structure:
x nt!*shared*
8055c6e0 nt!MmSharedUserDataPte = 
805360d8 nt!ExAcquireSharedStarveExclusive = 
8056094c nt!MmTransitionSharedPagesPeak = 
...

dd 8055c6e0  l1
8055c6e0  e100b498

dt -r nt!_MMPTE e100b498
...
+0x000 Flush            : _HARDWARE_PTE
+0x000 Valid            : 0y1
+0x000 Write            : 0y0
+0x000 Owner            : 0y0
+0x000 WriteThrough     : 0y0
+0x000 CacheDisable     : 0y0
+0x000 Accessed         : 0y1
+0x000 Dirty            : 0y0
+0x000 LargePage        : 0y0
+0x000 Global           : 0y1
+0x000 CopyOnWrite      : 0y0
+0x000 Prototype        : 0y0
+0x000 reserved0        : 0y0
+0x000 PageFrameNumber  : 0y00...1000001 (0x41)
+0x000 reserved1        : 0y10...0000000 (0x2000000)
+0x000 LowPart          : 0x41121
+0x004 HighPart         : 0x80000000

!pfn 41
PFN 00000041 at address 81AE671C
flink       00000023  blink / share
count 0000003C  pteaddress C07FEF80
reference count 0001   Cached     color 0
restore pte 00000080
containing page        00074F  Active      P
Shared

!pte C07FEF80
  VA ffdf0000
PDE at 00000000C0603FF0    PTE at 00000000C07FEF80
contains 000000000074F163  contains 0000000000041163
pfn 74f        -G-DA--KWEV    pfn 41         -G-DA--KWEV

And here we've got the kernel address, we can dump the shared space by:
dt nt!_kuser_shared_data ffdf0000  (KERNEL MODE ADDR)
+0x000 TickCountLow     : 0x3f7443d
+0x004 TickCountMultiplier : 0xfa00000
+0x008 InterruptTime    : _KSYSTEM_TIME
+0x014 SystemTime       : _KSYSTEM_TIME
+0x020 TimeZoneBias     : _KSYSTEM_TIME
+0x02c ImageNumberLow   : 0x14c
+0x02e ImageNumberHigh  : 0x14c
+0x030 NtSystemRoot     : [260] 0x43
+0x238 MaxStackTraceDepth : 0
+0x23c CryptoExponent   : 0
+0x240 TimeZoneId       : 2
+0x244 Reserved2        : [8] 0
+0x264 NtProductType    : 1 ( NtProductWinNt )
+0x268 ProductTypeIsValid : 0x1 ''
+0x26c NtMajorVersion   : 5
+0x270 NtMinorVersion   : 1
+0x274 ProcessorFeatures : [64]  ""
+0x2b4 Reserved1        : 0x7ffeffff  (USER MODE ADDRESS: 0x7ffe0000)
....

As you can see the structure has a self reference pointer for user mode addressing. But we need to 64k realign it before using it because of its allocation size (see vmmap output figure), so:
?0x7ffeffff& (@@(~(0x10000-1)))
Evaluate expression: 2147414016 = 7ffe0000
Dumping it at this address we get the exact same content as before:
dt nt!_kuser_shared_data 0x7ffe0000 
+0x000 TickCountLow     : 0x3f7443d
+0x004 TickCountMultiplier : 0xfa00000
+0x008 InterruptTime    : _KSYSTEM_TIME
+0x014 SystemTime       : _KSYSTEM_TIME
+0x020 TimeZoneBias     : _KSYSTEM_TIME
+0x02c ImageNumberLow   : 0x14c
+0x02e ImageNumberHigh  : 0x14c
+0x030 NtSystemRoot     : [260] 0x43
+0x238 MaxStackTraceDepth : 0
+0x23c CryptoExponent   : 0
+0x240 TimeZoneId       : 2
+0x244 Reserved2        : [8] 0
+0x264 NtProductType    : 1 ( NtProductWinNt )
+0x268 ProductTypeIsValid : 0x1 ''
+0x26c NtMajorVersion   : 5
+0x270 NtMinorVersion   : 1
+0x274 ProcessorFeatures : [64]  ""
+0x2b4 Reserved1        : 0x7ffeffff
+0x2b8 Reserved3        : 0x80000000
+0x2bc TimeSlip         : 0
+0x2c0 AlternativeArchitecture : 0 ( StandardDesign )
+0x2c8 SystemExpirationDate : _LARGE_INTEGER 0x0
+0x2d0 SuiteMask        : 0x110
+0x2d4 KdDebuggerEnabled : 0 ''
+0x2d5 NXSupportPolicy  : 0x2 ''
+0x2d8 ActiveConsoleId  : 0
+0x2dc DismountCount    : 0
+0x2e0 ComPlusPackage   : 0xffffffff
+0x2e4 LastSystemRITEventTickCount : 0x3df72600
+0x2e8 NumberOfPhysicalPages : 0x3f73c
+0x2ec SafeBootMode     : 0 ''
+0x2f0 TraceLogging     : 0
+0x2f8 TestRetInstruction : 0xc3
+0x300 SystemCall       : 0x7c90e510
+0x304 SystemCallReturn : 0x7c90e514
+0x308 SystemCallPad    : [3] 0
+0x320 TickCount        : _KSYSTEM_TIME
+0x320 TickCountQuad    : 0
+0x330 Cookie           : 0xe066d175
The output from vmmap shows us the allocated size and the structure size of this special area:

sábado, 2 de julho de 2011

Cracking a Pimp

Just came back from vacations and found the Pimp My Crackme contest. Although I'm not in time to participate in the competition, being a follower of the first prize authors work, I decided to take a look at their challenge.
What I found was a really interesting and defying piece of protection software, and I think worth mentioning in a post about cracking and RE.
What I'll be referring here though, will be just a specific piece of code that blocks the reverser from tracing from withing some debuggers, Olly being one of the affected, and not the entire puzzle cracking. If you're using Windbg you won't have to deal with this.

This specific issue relates to the authors having used a known issue where some debuggers get lost or fail to synchronize when an LDT is used to detour the execution path.

The reversed source code to setup the LDT entry is this:
codeSegment = getCodeSegment(); // CS=0x1B
GetThreadSelectorEntry(GetCurrentThread(),
                    codeSegment,
                    &SelectorEntry);
SelectorEntry.LimitLow = 0xFFEF;
SelectorEntry.HighWord.Bytes.Flags2.LimitHi = 0x7;
pHandle = GetCurrentProcess();
error = setLDT(pHandle,
            (int *)0x7FF,
             &SelectorEntry); // LDT = 0x7F8
...
memcpy(farCallClone, farCall, 0x1Fu);
In process, we've got this selector before setup:
And this afterwords:
Flags2 in LDT_ENTRY comprises LimitHi, Sys, Reserved_0, Default_Big, and Granularity in the selector entry. Being its definition:
DWORD LimitHi :4;
DWORD Sys :1;
DWORD Reserved_0 :1;
DWORD Default_Big :1;
DWORD Granularity  :1;
So they're setting up limitHi = 0x7 for selector entry 0x7FF. What this means to Olly, is that it fails to trace when far jumping, and consequently we fail to use it to find the correct key. To bypass this "protection" we need to fix the jumped segments to be the same than our start up segment. There are a couple of ways to do this, the simplest one I found for this case is just to patch position:
009200DD call far 07FF:00000000
to our original execution segment:
009200DD call far 001B:00000000
Now, the funny part is that they have escalated the problem using multiple segments. I'm not going to delve much in the cracking process or explain how the protection works, but in order to explain how the various segments are utilized, I need to refer that the core of the protection lies in a virtual machine architecture. This virtual machine has a set of functions that virtualize it's domain operations. Aside from other interesting approaches used, this functions where laid out, each one on it's own LDT segment. And shuffled after key validation. So you can imagine how Olly must feel, always jumping around segments.
How can we bypass this? As I pointed out before, we need to maintain execution to our home segment 0x1b. How can we do this? patching the key function that distributes all the work of the VM: I called it CallVMInstruction.
Replace this function with this code:
0040CD95 mov word ptr ss:[ebp-2],1B
0040CD9B jmp short pimp_cra.0040CDC1
0040CD9D nop
0040CD9E nop
0040CD9F nop
0040CDA0 push ebp
0040CDA1 mov ebp,esp
0040CDA3 sub esp,14
0040CDA6 mov eax,[arg.1]
0040CDA9 and al,0F8 
0040CDAB shr eax,1
0040CDAD mov edi,eax
0040CDAF shl eax,2
0040CDB2 add eax,edi 
0040CDB4 lea eax,dword ptr ds:[eax+91FE14] 
0040CDBA mov eax,dword ptr ds:[eax] 
0040CDBC mov dword ptr ss:[ebp-6],eax 
0040CDBF jmp short pimp_cra.0040CD95
0040CDC1 mov edi,dword ptr ds:[AF8EF8]
0040CDC7 push [arg.2]
0040CDCA call far fword ptr ss:[ebp-6]
What this code does is it resolves dynamically the function address to our home segment, based on the segment index passed as an argument to the dispatcher and retained in a VM call dispatcher table.

With this you can set a breakpoint at address 0x0040CDCA. Now just relax and wait for the key validation, and you can now trace all the virtual machine operations.

Finally two simple last patches in order to prepare for the flush and hashing operations:
Replace the code at address:
00403046 mov eax,9200C0
0040304B nop
0040304C nop
0040304D nop
0040304E nop
0040304F nop
00403050 nop

00403243 mov eax,9200C0
00403248 nop
If you find any others function that need to be patched, now you know what to do. Consider it an exercise.

Just a side note about a second problem that I found while debugging the crackme. The authors used a far call stub function for the previously discussed purpose. They rebased this function to address zero. Ollydbg gets totally lost when trying to trace a zero base address. The way I found to successfully trace the stub calls was to instead of setting a breakpoint in address zero, I set the breakpoint in the second instruction, address 4, at lea eax,dword ptr ds:[eax*4+8] instruction.
The reversed code for it is again presented here:
...

BaseAddress = 4;
RegionSize = 4092;
pHandle = GetCurrentProcess();
error = NtAllocateVirtualMemory(pHandle,
              &BaseAddress,
              0,
              &RegionSize,
              MEM_TOP_DOWNMEM_RESERVEMEM_COMMIT,
              PAGE_EXECUTE_READWRITE);
if ( error >= 0 )
{
 farCallClone = 0;
 memcpy(farCallClone,
        farCall,
        0x1F);
....

Good look finding the correct key.

quinta-feira, 16 de junho de 2011

Exploding Windows 7 interactive sessions

I always wondered if Windows 7, supposedly having the same core than it's server counterpart, was somehow capable of supporting more than one interactive session. I'd speculate whether Microsoft had changed it's core not to limit functionality but to present to the end user a lighter kernel, faster and less resource demanding.

I was wrong. This post presents the proof that more than one interactive session is indeed possible within Windows 7.

Considering this, I remembered the many times I needed to login interactively into a client machine while the user was logged in. How many reasons where there? How many helpdesk calls, tests, validations, etc. without having to lock or logoff the user? How many times have I prayed for some way to bypass this limitation? Hundred of times. Particularly for the server editions when the 2 remote sessions limit (plus 1 for the console) was hit. What was more annoying? Killing remote sessions or be killed by someone else that also needed to enter?

But the most important point I'd like to raise with this post, is that my hack targets Winlogon, opposing the traditional and obvious target that aims to Remote Desktop service (termsrv.dll). Winlogon has become the master in this domain. Isn't this an error? Should Winlogon have such power? This seems contrary to Microsoft modular policy.

So, the figure shows you the target as Windows 7 Professional, and I’ve got two active sessions opened, one in console and the other remote.
What are the possibilities then? Well, as usually said, your imagination is the limit. In fact your memory is, but this approach allows for theoretically unlimited usage of terminal interactive sessions.

To use the tool, you need to connect thru RDP or the console and establish a second session. Before logging in, identify the new opened session and remember the PID of the newly created winlogon.exe process. Run the tool as this:

You can login now and as you’ll see, you’ll be in a newly fresh interactive session.
No error messages, no one being killed or locked.
I'm not going to delve more in the subject, nor will I be sharing the tool I built like in the other posts because I don't want to get in trouble with Microsoft, but for those willing to send me an email requesting the tool, I'll share it with you.

PS: being a PoC the tool only works on Windows 7 (yeh!) SP1 32 bits.

quinta-feira, 9 de junho de 2011

Patchguard red flags

Having a 64bit machine for a month now, and in need to perform some tests on Windows x64 kernel, I decided it was time to take on Patchguard(PG). I started by searching the Internet for ways to disable it, and to my suprise there was almost nothing up to date on the subject.
I did found one working patch on PG by Fyyre. Pretty awesome work, I'd say. Basically he says to look for cross references of InitSafeBootMode and patch the one he points as critical. I found it pretty simple to follow, and wondered how a multi-billion dollar product can be broken so easily.
So, I started looking for tips in code that could denounce PG hot paths, and I found one:

Looking for cross references of KdDebuggerNotPresent. There are a bunch of them, but restricting the search to the following operations you get the critical path that enables PG:
1. cmp operations,
2. followed by conditional jump,
3. followed by a unconditional jump to the it's own location, locking the cpu.

The only two functions that relate to this, are KiFilterFiberContext and KiEnablePatchGuard.
It is as Microsoft didn't want us to enter this functions with a debugger, which is understandable as that could compromise PG, but they should at least not leave this red flags behind.