kevoreilly / capemon

capemon: CAPE's monitor
GNU General Public License v3.0
102 stars 49 forks source link

Capemon Testing Question #69

Closed 0xGotcha closed 1 year ago

0xGotcha commented 1 year ago

I am interested in testing Yara rules that involve the debugging. Is there any specific technique or development path you follow to test the yara debugging rules? Example would be GuLoader.

0xGotcha commented 1 year ago

Tutorials and other walkthrough are welcome. having a hard time finding information.

kevoreilly commented 1 year ago

Hi 0xGotcha - happy to hear you are interested in cape's debugger, perhaps its most powerful weapon. However you highlight the lack of documentation or tutorials. I have not yet made this type of material, it is long overdue. There is now such a huge subject to cover... But as this is something that will require a lot of time and work, the best I can do is try to give you a quick run through here.

But Guloader is not a good example as it is perhaps one of the biggest challenges capemon has overcome, and the current versions are not working so I need to revisit this loader! It's on my to-do list even higher than the documentation!

So let's use a simpler example, of course I loved the sound of your Ludus, training school for debugger gladiators. Let's trace the hardware breakpoint detection code whilst using.... hardware breakpoints!

image

A quick yara sig from this code might be:

rule Ludus
{
    meta:
        cape_options = "bp0=$hwbp"
    strings:
        $hwbp = {74 7A 48 83 BC 24 88 00 00 00 00 75 37 48 83 BC 24 90 00 00 00 00 75 2C 48 83 BC 24 98 00 00 00 00 75 21 48 83 BC 24 A0 00 00 00 00 75 16 48 83 BC 24 A8 00 00 00 00 75 0B 48 83 BC 24 B0 00 00 00 00 74 38}
    condition:
        uint16(0) == 0x5A4D and all of them
}

Here we just use the fairly distinct bytes in the drx comparisons to set our hardware breakpoint with bp0=$hwbp

CAPE Sandbox - Debugger log: Tue Nov 21 12:40:59 2023
Breakpoint 0 hit by instruction at 0x00007FF7DF1863D9 (thread 1316) RAX=0x1 RBX=0x178e5bdfbb0 "HardwareDebugRegisters" RCX=0x6f27ab416a970000 RDX=0x178e74f0000 RDI=0x7 RSP=0x4c444fed50 *RSP=0 R8=0xffffffff R9=0x1 R10=0x178e74f0000 R11=0x4c444fe130 R12=0x178e5bd72b0 R14=0xe R15=0x178e5bd72c0 "x" Xmm0.Low=0x3412000000 Xmm1.Low=0x521200007ffc481c Xmm1.High=0x7ff7df1863d700
Break at 0x00007FF7DF1863D9 in 51d003e5a44a9bab864434e0.exe (RVA 0x63d9, thread 1316, ImageBase 0x00007FF7DF180000)
0x00007FF7DF1863D9  747A                     JZ        0x7c                          
0x00007FF7DF1863DB  4883BC248800000000       CMP       QWORD [RSP+0x88], 0x0         
0x00007FF7DF1863E4  7537                     JNZ       0x39                          
0x00007FF7DF1863E6  4883BC249000000000       CMP       QWORD [RSP+0x90], 0x0         
0x00007FF7DF1863EF  752C                     JNZ       0x2e                          
0x00007FF7DF1863F1  4883BC249800000000       CMP       QWORD [RSP+0x98], 0x0         
0x00007FF7DF1863FA  7521                     JNZ       0x23                          
0x00007FF7DF1863FC  4883BC24A000000000       CMP       QWORD [RSP+0xa0], 0x0         
0x00007FF7DF186405  7516                     JNZ       0x18                          
0x00007FF7DF186407  4883BC24A800000000       CMP       QWORD [RSP+0xa8], 0x0         
0x00007FF7DF186410  750B                     JNZ       0xd                           
0x00007FF7DF186412  4883BC24B000000000       CMP       QWORD [RSP+0xb0], 0x0         
0x00007FF7DF18641B  7438                     JZ        0x3a                          
0x00007FF7DF186455  488B8C2410050000         MOV       RCX, [RSP+0x510]               RCX=0x3d984fd62981
0x00007FF7DF18645D  4833CC                   XOR       RCX, RSP                       RCX=0x3dd40b99c4d1
0x00007FF7DF186460  E8DB9B0100               CALL      0x00007FF7DF1A0040             RCX=0x3dd40b99c4d10000
0x00007FF7DF186465  4881C428050000           ADD       RSP, 0x528                     RSP=0x4c444ff278 "*v" *RSP=0x7ff7df18762a
0x00007FF7DF18646C  C3                       RET 

Boom it really is that easy. Here cape cruises past this check because of the defences in the GetThreadContext hook, but let's imagine that this was actually detecting bp0 with that first jnz. So we need to 'nop' or skip that instruction so now we set the breakpoint at an offset of 11 to break after the first two instructions with bp0=$hwbp+11 (alternatively we could of course change the yara pattern). We add an action to skip the instruction, and a count to stop tracing immediately.

rule Ludus
{
    meta:
        cape_options = "bp0=$hwbp+11,action0=skip,count=1"
    strings:
        $hwbp = {74 7A 48 83 BC 24 88 00 00 00 00 75 37 48 83 BC 24 90 00 00 00 00 75 2C 48 83 BC 24 98 00 00 00 00 75 21 48 83 BC 24 A0 00 00 00 00 75 16 48 83 BC 24 A8 00 00 00 00 75 0B 48 83 BC 24 B0 00 00 00 00 74 38}
    condition:
        uint16(0) == 0x5A4D and all of them
}
CAPE Sandbox - Debugger log: Tue Nov 21 18:37:28 2023
Breakpoint 0 hit by instruction at 0x00007FF77CC663E4 (thread 7200) RAX=0x1 RBX=0x1ef9c34fff0 "HardwareDebugRegisters" RCX=0x2b5029c0b2d50000 RDX=0x1ef9dd60000 RDI=0x7 RSP=0x902a8ff050 *RSP=0 R8=0xffffffff R9=0x1 R10=0x1ef9dd60000 R11=0x902a8fe430 R12=0x1ef9c350b90 R14=0xe R15=0x1ef9c350ba0 "x" Xmm0.Low=0x3412000000 Xmm0.High=0x65000000000000 Xmm1.Low=0x521200007ffc481c Xmm1.High=0x7ff77cc663d700
Break at 0x00007FF77CC663E4 in 51d003e5a44a9bab864434e0.exe (RVA 0x63e4, thread 7200, ImageBase 0x00007FF77CC60000)
0x00007FF77CC663E4  7537                     JNZ       0x39                          
ActionDispatcher: skipping instruction.
0x00007FF77CC663E6  4883BC249000000000       CMP       QWORD [RSP+0x90], 0x0         
Trace: Single-step limit reached (1), releasing.

Hey presto, we have a 'bypass' that would force the breakpoint to remain undetected! I hope that helps.