The looong analysis of (white-hat) cracking software

So, I’ve wanted to have some fun and spend many long hours in the weekend trying to (white-hat 😉 ) crack a random software that comes with an evaluation period 😀 I’ve chosen a not so difficult one which would check against a response from the web for its verification or anything like that, but rather one that just stores a serial number (if entered) locally and just checks that for validation. Anything more complicated would take many, many days, weeks, lives, etc. =))

For the purpose of privacy and so on, I won’t reveal the name of this software and we’ll just name this SomeProc.exe and which is a Win32 x64 native compiled image (PE). The purpose of it is irrelevant, but what is relevant to us here, is that it has a UI and that sometimes makes things simpler. That is because we can just try to check if the UI shows (and it usually does) certain strings like “evaluation“, “register“, etc. – things of this nature. This is important because we can search for these strings in the process itself (unless they have been somehow obfuscated … but at the right point if searching long enough, we might still find them …).

NOTE: I’m using public symbols for the Windows modules, so no “magic” involved: Microsoft Public Symbol Server

Other methods would be using different anaysis tools of what processes do – like tools from the System Internals Suite – more specific usually Process Monitor helps a lot in an initial investigation or even later after already having some hints from other places (like process memory under a debugger, etc.). Another more than great and awesome tool for reverse engineering / malware analysis is IDA – check it out! 😀

Luckly enough, our SomeProc.exe displays the string “evaluation copy” in the UI. That’s a good place to start as any I guess. These types of reverse engineering analysis tasks can take ages and have many trial and error moments which all maybe get you closer to the next clue or just leave you frustrated after many hours.

When it comes to non-native compiled processes (ex. .NET Framework) or others where we can simply use an IL (Intermediate Language) Dissassembler (or whatever decompiler can be used depending on what code we are talking about), things are pretty easy and we can see some relativley clear code (like C# decompiled from IL) and all is good and well. When it comes to native compiled processes (machine code) without having public or private symbols at all, makes for a nice “hunt” in machine code and assembly interpretation fun 😀

Right … so let’s start with looking for strings under the debugger – I’m using WinDbgX and I’m starting the process under it. It breaks just on process startup (before calling “main” (or whatever entry point if it has been changed) from ntdll.dll). ntdll.dll is the user mode wrapper around a process on Windows which handles everything a process needs to start (memory, args, etc.) and which calls the entrypoint of the process (WinPE – Win Printable Executable) and it’s also the one making the calls into Kernel.

So, in order to search the process memory for strings using the memory search functionality of WinDbg, we’ll need to get the addresses (start & end) of where the image was loaded (we might need to search the EXE and each own DLL it uses – we might need to search all it’s images … not only the starting process – EXE). So, let’s get the start & end addresses of our loaded SomeProc.exe image in memory:

0:000> lmtm SomeProc 
start             end                 module name
00007ff7`70600000 00007ff7`7091d000   SomeProc    Tue Feb 12 11:24:14 2023 (52FE126F)

Alright, using these now, let’s perform a search for the UNICODE string “evaluation” like so:

0:000> s -u 00007ff7`70600000 00007ff7`7091d000 "eval"
00007ff7`709151ac  0065 0076 0061 006c 0075 0061 0074 0069  e.v.a.l.u.a.t.i.

Niiiice, very lucky, usually it’s not that lucky, but again, I’ve chosen something simple for the sake of this blog post and for not finishing my analysis when I’ll be 80 years old … =)) We can resolve the entire string using “du” which dumps UNICODE strings from a certain memory address (displays until terminating null character 0x0000 – 2 bytes in UNICODE):

0:000> du 00007ff7`709151ac  
00007ff7`709151ac  "evaluation copy"

HA! There we go, confirmed, it’s the string that we see in the UI “evaluation copy“. So, what we can do now, is pretty interesting because we would be interested to see where at some point in execution of the code, this memory location will be read … soooo, let’s put a breakpoint of type break on access when 1st byte from this address is being read and then “g” GO to let the process execute and see where we end up:

0:000> ba r1 00007ff7`709151ac

0:000> g
Breakpoint 1 hit
ntdll!memcpy+0x29:
00007ffa`ba6b59a9 420f104c02f0    movups  xmm1,xmmword ptr [rdx+r8-10h] ds:00007ff7`709151ba=00790070006f00630020006e006f0069

Let’s also display the CPU registers and the current stack (@RSP – stack pointer) of the current instruction location (@RIP – instruction pointer):

0:000> r
rax=00007ff7707cd010 rbx=000000000000001e rcx=00007ff7707cd010
rdx=00007ff7709151ac rsi=00000000000003ff rdi=00007ff7707cd010
rip=00007ffaba6b59a9 rsp=000000446e4f6a28 rbp=00007ff770600000 
 r8=000000000000001e  r9=00007ff7709150a0 r10=0000000000000001
r11=000000446e4f6a00 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000369
iopl=0         nv up ei ng nz na pe cy
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000283
ntdll!memcpy+0x29:
00007ffa`ba6b59a9 420f104c02f0    movups  xmm1,xmmword ptr [rdx+r8-10h] ds:00007ff7`709151ba=00790070006f00630020006e006f0069

0:000> k
Child-SP          RetAddr               Call Site
00000044`6e4f6a28 00007ffa`b8062624     ntdll!memcpy+0x29
00000044`6e4f6a30 00007ffa`ba097ec2     KERNELBASE!LoadStringBaseExW+0xd4
00000044`6e4f6aa0 00007ff7`706a49c9     USER32!LoadStringW+0x12
00000044`6e4f6ae0 00007ff7`70700e26     SomeProc+0xa49c9 
00000044`6e4f6b20 00007ff7`70659fb8     SomeProc+0x100e26
00000044`6e4f8360 00007ff7`7070163a     SomeProc+0x59fb8
00000044`6e4fc970 00007ff7`707188c2     SomeProc+0x10163a
00000044`6e4ffaa0 00007ffa`b8ed26bd     SomeProc+0x1188c2
00000044`6e4ffae0 00007ffa`ba66dfb8     KERNEL32!BaseThreadInitThunk+0x1d
00000044`6e4ffb10 00000000`00000000     ntdll!RtlUserThreadStart+0x28

Alright, so this is where the process is loading the string – it’s interesting to see what it would do in the execution after it loads this value which it is doing by calling USER32!LoadStringW from some location inside of it (remember, no symbols – so we only see some OFFSET into the image (start + OFFSET). We can see that we are calling from this location SomeProc+0xa49c9 – so, let’s see the code here:

0:000> u SomeProc+0xa49c9
SomeProc+0xa49c9:
00007ff7`706a49c9 85c0            test    eax,eax
00007ff7`706a49cb 7515            jne     SomeProc+0xa49e2 (00007ff7`706a49e2)
00007ff7`706a49cd 488b0d944c1200  mov     rcx,qword ptr [SomeProc+0x1c9668 (00007ff7`707c9668)]
00007ff7`706a49d4 448bcf          mov     r9d,edi
00007ff7`706a49d7 4c8bc3          mov     r8,rbx
00007ff7`706a49da 8bd6            mov     edx,esi
00007ff7`706a49dc ff155e8f0900    call    qword ptr [SomeProc+0x13d940 (00007ff7`7073d940)]
00007ff7`706a49e2 488b6c2448      mov     rbp,qword ptr [rsp+48h]

We can see that after we load this, we are going to check if the return value of the USER32!LoadStringW function was 0 or something else by doing a “test eax, eax” where EAX means that we are addressing just 32bits of the otherwhise 64bits register RAX (as we are in a x64 process). Note that this is done because by convension, compilers store return values of functions in the “AX” register – here on x64 – the RAX register. So, let’s see if we will jump or not in the next instruction (JNE – “jne SomeProc+0xa49e2“) by checking the value of the register and addressing it in its 32bit form (just like the code does). In oder to do that, we’ll need to “go” there in the execution. There are a couple of ways to do this, but I’ll just chose the easiest one and put a breakpoint on the return address of the call to USER32!LoadStringW which should end up exactly @ SomeProc+0xa49c9:

0:000> bp 00007ff7`706a49c9

0:000> g
Breakpoint 1 hit
SomeProc+0xa49c9:
00007ff7`706a49c9 85c0            test    eax,eax

Yup, here we are, so let’s check the value of EAX as we discussed:

0:000> r @eax
eax=f

Alright, it’s non-zero (0xF) which is expected here as per USER32!LoadStringW documentation, if it does not fail (would return 0), it returns the number of characters in the string + NULL termination character (0xF = 16 => “evaluation copy” + “\0“).

Alright, this hasn’t told us anything we need, but it’s a good place to demonstrate the flow and what to look at here for further reference 🙂

At this point, we are here – when looking into the dissassembly window of WinDbg where we can follow the execution and step through the code to analyze its execution flow:

00007ff7`706a49c3 ff15778f0900   call    qword ptr [7FF77073D940h]
00007ff7`706a49c9 85c0           test    eax, eax
00007ff7`706a49cb 7515           jne     00007FF7706A49E2
00007ff7`706a49cd 488b0d944c1200 mov     rcx, qword ptr [7FF7707C9668h]
00007ff7`706a49d4 448bcf         mov     r9d, edi
00007ff7`706a49d7 4c8bc3         mov     r8, rbx
00007ff7`706a49da 8bd6           mov     edx, esi
00007ff7`706a49dc ff155e8f0900   call    qword ptr [7FF77073D940h]
00007ff7`706a49e2 488b6c2448     mov     rbp, qword ptr [rsp+48h]
00007ff7`706a49e7 488bc3         mov     rax, rbx
00007ff7`706a49ea 488b5c2440     mov     rbx, qword ptr [rsp+40h]
00007ff7`706a49ef 488b742450     mov     rsi, qword ptr [rsp+50h]
00007ff7`706a49f4 4883c430       add     rsp, 30h
00007ff7`706a49f8 5f             pop     rdi
00007ff7`706a49f9 c3             ret

As we can see, we’ll be calling USER32!LoadStringW again (as it’s @ 7FF77073D940h) to get some other string from the module via Resource ID (check documentation if confused). Because shortly after we are calling RET (function return – OP Code 0xc3), it looks like the function we are currently in of this process, is just loading string resources probably … and nothing more interesting than that. So, what will happen afterwards?! …

Now, let’s step over this and continue from its calling function @ SomeProc+0x100e26 and also confirm that the previous function returned the string we are expecting – just for sanity check and understanding:

0:000> t
SomeProc+0x100e26:
00007ff7`70700e26 488bd0          mov     rdx,rax

0:000> du @rax
00007ff7`707cd010  "evaluation copy"

Stepping a little further, we end up with an interesting place where we are loading 0x200 (= 512 … interesint) into R9 register and then call another function:

0:000> u @rip
SomeProc+0x100e2e:
00007ff7`70700e2e 41b800020000    mov     r8d,200h
00007ff7`70700e34 e8ab9bfaff      call    SomeProc+0xaa9e4 (00007ff7`706aa9e4)
00007ff7`70700e39 4c8bc7          mov     r8,rdi
00007ff7`70700e3c 488d1521f90400  lea     rdx,[SomeProc+0x150764 (00007ff7`70750764)]
00007ff7`70700e43 488d8c2420040000 lea     rcx,[rsp+420h]
00007ff7`70700e4b e86c9bfaff      call    SomeProc+0xaa9bc (00007ff7`706aa9bc)
00007ff7`70700e50 4c8bc7          mov     r8,rdi
00007ff7`70700e53 488d542420      lea     rdx,[rsp+20h]

We will unassemble (as we know from the CALL instruction that this () will be the function entrypoint – so we unasssemble using “uf” to see the entire function:

0:000> uf SomeProc+0xaa9e4
SomeProc+0xaa9e4:
00007ff7`706aa9e4 4533c9          xor     r9d,r9d
00007ff7`706aa9e7 4d85c0          test    r8,r8
00007ff7`706aa9ea 7423            je      SomeProc+0xaaa0f (00007ff7`706aaa0f)  Branch

SomeProc+0xaa9ec:
00007ff7`706aa9ec 4983e801        sub     r8,1
00007ff7`706aa9f0 7419            je      SomeProc+0xaaa0b (00007ff7`706aaa0b)  Branch

SomeProc+0xaa9f2:
00007ff7`706aa9f2 482bd1          sub     rdx,rcx

SomeProc+0xaa9f5:
00007ff7`706aa9f5 0fb7040a        movzx   eax,word ptr [rdx+rcx]
00007ff7`706aa9f9 6685c0          test    ax,ax
00007ff7`706aa9fc 740d            je      SomeProc+0xaaa0b (00007ff7`706aaa0b)  Branch

SomeProc+0xaa9fe:
00007ff7`706aa9fe 668901          mov     word ptr [rcx],ax
00007ff7`706aaa01 4883c102        add     rcx,2
00007ff7`706aaa05 4983e801        sub     r8,1
00007ff7`706aaa09 75ea            jne     SomeProc+0xaa9f5 (00007ff7`706aa9f5)  Branch

SomeProc+0xaaa0b:
00007ff7`706aaa0b 66448909        mov     word ptr [rcx],r9w

SomeProc+0xaaa0f:
00007ff7`706aaa0f c3              ret  Branch

So … now follows a loooong process of stepping through the code and anlyzing what it does next until we hoooopefully reach an interesting point which would give us some hints or something …

After stepping from call to call and code and so on (we can use “pc” to step-jump from call to call), I ended up in USER32.dll which is part of the Windows GUI, so we are already starting the actual UI and passing Windows Messeges (ended up in USER32!SendMessageW) – that (most likely) means that we are past the place of interest where the “validation verification registration key whatever …” was done … – but … at last by comparing stacks from before (see in snippets from above), we can see that the (or rather one of the) “bigger” most important handling / decision making functions, might be somewhere around @ SomeProc+0x10163a because this was on the stack while we were loading the “evaluation copy” string and during many other function SomeProc owned calls and now we ended up in USER32.dll and it’s still on the stack:

0:000> k
 # Child-SP          RetAddr               Call Site
00 000000a7`061d84e8 00007ff7`7065a012     USER32!SendMessageW
01 000000a7`061d84f0 00007ff7`7070163a     SomeProc+0x5a012
02 000000a7`061dcb00 00007ff7`707188c2     SomeProc+0x10163a
03 000000a7`061dfc30 00007ffa`b8ed26bd     SomeProc+0x1188c2
04 000000a7`061dfc70 00007ffa`ba66dfb8     KERNEL32!BaseThreadInitThunk+0x1d
05 000000a7`061dfca0 00000000`00000000     ntdll!RtlUserThreadStart+0x28

So, I noted down an interesting place (function) to look at closer and I’ve noticed that it’s being called multiple times SomeProc+0xaa9e4 (check/search in above snippets for it). What I’ve noticed was that at some point, between calls to it, at some point we load bcryptPrimitives.dll DLL which is a Windows DLL that is used for cryptographic services (encryption/decryption/etc.) – as can also be seen if we display the module information for it:

0:000> lmDvm bcryptPrimitives
Browse full module list
start             end                 module name
00007ffa`b7f60000 00007ffa`b7fdb000   bcryptPrimitives   (deferred)             
    Image path: C:\WINDOWS\System32\bcryptPrimitives.dll
    Image name: bcryptPrimitives.dll
    Browse all global symbols  functions  data
    Image was built with /Brepro flag.
    Timestamp:        46D130CD (This is a reproducible build file hash, not a timestamp)
    CheckSum:         0008638E
    ImageSize:        0007B000
    File version:     10.0.22621.1105
    Product version:  10.0.22621.1105
    File flags:       0 (Mask 3F)
    File OS:          40004 NT Win32
    File type:        2.0 Dll
    File date:        00000000.00000000
    Translations:     0409.04b0
    Information from resource tables:
        CompanyName:      Microsoft Corporation
        ProductName:      Microsoft® Windows® Operating System
        InternalName:     bcryptprimitives.dll
        OriginalFilename: bcryptprimitives.dll
        ProductVersion:   10.0.22621.1105
        FileVersion:      10.0.22621.1105 (WinBuild.160101.0800)
        FileDescription:  Windows Cryptographic Primitives Library
        LegalCopyright:   © Microsoft Corporation. All rights reserved.

So, let’s restart (.restart) the process under the debugger, set a breakpoint on SomeProc+0xaa9e4 and see how many times it is called and when the bcryptPrimitives.dll DLL is loaded during these calls (seems to be on the 5th call):

0:000> .restart

0:000> bp SomeProc+0xaa9e4

0:000> g
ModLoad: 00007ffa`b9180000 00007ffa`b91b2000   C:\WINDOWS\System32\IMM32.DLL
ModLoad: 00007ffa`b6900000 00007ffa`b6913000   C:\WINDOWS\SYSTEM32\UMPDC.dll
Breakpoint 0 hit
SomeProc+0xaa9e4:
00007ff7`706aa9e4 4533c9          xor     r9d,r9d

0:000> g
Breakpoint 0 hit
SomeProc+0xaa9e4:
00007ff7`706aa9e4 4533c9          xor     r9d,r9d

0:000> g
Breakpoint 0 hit
SomeProc+0xaa9e4:
00007ff7`706aa9e4 4533c9          xor     r9d,r9d

0:000> g
ModLoad: 00007ffa`b5a20000 00007ffa`b62e8000   C:\WINDOWS\SYSTEM32\windows.storage.dll
ModLoad: 00007ffa`b58e0000 00007ffa`b5a1e000   C:\WINDOWS\SYSTEM32\wintypes.dll
ModLoad: 00007ffa`b6b50000 00007ffa`b6b68000   C:\WINDOWS\SYSTEM32\kernel.appcore.dll
ModLoad: 00007ffa`b7f60000 00007ffa`b7fdb000   C:\WINDOWS\System32\bcryptPrimitives.dll
ModLoad: 00007ffa`b7700000 00007ffa`b774e000   C:\WINDOWS\SYSTEM32\CFGMGR32.dll
ModLoad: 00007ffa`b8d10000 00007ffa`b8dc0000   C:\WINDOWS\System32\clbcatq.dll
ModLoad: 00007ffa`b3120000 00007ffa`b3220000   C:\WINDOWS\system32\propsys.dll
ModLoad: 00007ffa`b8f90000 00007ffa`b9034000   C:\WINDOWS\System32\sechost.dll
ModLoad: 00007ffa`81da0000 00007ffa`81e40000   C:\Windows\System32\Windows.FileExplorer.Common.dll
ModLoad: 00007ffa`a97f0000 00007ffa`a98db000   C:\Windows\System32\Windows.StateRepositoryPS.dll
ModLoad: 00007ffa`aecc0000 00007ffa`aecfd000   C:\WINDOWS\SYSTEM32\windows.staterepositoryclient.dll
ModLoad: 00007ffa`b7980000 00007ffa`b79a1000   C:\WINDOWS\SYSTEM32\profapi.dll
ModLoad: 00007ffa`afd20000 00007ffa`afd3e000   C:\WINDOWS\SYSTEM32\MPR.dll
ModLoad: 00007ffa`9feb0000 00007ffa`9fed9000   C:\WINDOWS\System32\p9np.dll
ModLoad: 00007ffa`b1b40000 00007ffa`b1b4c000   C:\WINDOWS\System32\drprov.dll
ModLoad: 00007ffa`aaee0000 00007ffa`aaef9000   C:\WINDOWS\System32\ntlanman.dll
ModLoad: 00007ffa`aad50000 00007ffa`aad6f000   C:\WINDOWS\System32\davclnt.dll
ModLoad: 00007ffa`b6580000 00007ffa`b65e6000   C:\WINDOWS\System32\WINSTA.dll
ModLoad: 00007ffa`b04b0000 00007ffa`b04ca000   C:\WINDOWS\System32\wkscli.dll
ModLoad: 00007ffa`ab8b0000 00007ffa`ab8c2000   C:\WINDOWS\SYSTEM32\cscapi.dll
ModLoad: 00007ffa`b6530000 00007ffa`b653c000   C:\WINDOWS\System32\netutils.dll
ModLoad: 00007ffa`b4e90000 00007ffa`b4f27000   C:\WINDOWS\SYSTEM32\apphelp.dll
ModLoad: 00007ffa`81af0000 00007ffa`81b0a000   C:\WINDOWS\system32\NetworkExplorer.dll
Breakpoint 0 hit
SomeProc+0xaa9e4:
00007ff7`706aa9e4 4533c9          xor     r9d,r9d

0:000> k
 # Child-SP          RetAddr               Call Site
00 00000018`3aafbd78 00007ff7`706aa9df     SomeProc+0xaa9e4
01 00000018`3aafbd80 00007ff7`70694243     SomeProc+0xaa9df
02 00000018`3aafbdb0 00007ff7`706ba059     SomeProc+0x94243
03 00000018`3aafbe00 00007ff7`706b990d     SomeProc+0xba059
04 00000018`3aafbf40 00007ff7`706ba249     SomeProc+0xb990d
05 00000018`3aafbf70 00007ff7`706b9ef1     SomeProc+0xba249
06 00000018`3aafbfa0 00007ff7`706b986a     SomeProc+0xb9ef1
07 00000018`3aafc810 00007ff7`70700f60     SomeProc+0xb986a
08 00000018`3aafcc70 00007ff7`707188c2     SomeProc+0x100f60
09 00000018`3aaffda0 00007ffa`b8ed26bd     SomeProc+0x1188c2
0a 00000018`3aaffde0 00007ffa`ba66dfb8     KERNEL32!BaseThreadInitThunk+0x1d
0b 00000018`3aaffe10 00000000`00000000     ntdll!RtlUserThreadStart+0x28

Now … on the 11th call to SomeProc+0xaa9e4, it looks like we load the ADVAPI32.dll DLL which is a Windows DLL responsible for a couple of things, but, most likely and usually used for interacting with the Windows Registry which makes things pretty interesting …

0:000> g
Breakpoint 0 hit
SomeProc+0xaa9e4:
00007ff7`706aa9e4 4533c9          xor     r9d,r9d

0:000> g
Breakpoint 0 hit
SomeProc+0xaa9e4:
00007ff7`706aa9e4 4533c9          xor     r9d,r9d

0:000> g
Breakpoint 0 hit
SomeProc+0xaa9e4:
00007ff7`706aa9e4 4533c9          xor     r9d,r9d

0:000> g
Breakpoint 0 hit
SomeProc+0xaa9e4:
00007ff7`706aa9e4 4533c9          xor     r9d,r9d

0:000> g
Breakpoint 0 hit
SomeProc+0xaa9e4:
00007ff7`706aa9e4 4533c9          xor     r9d,r9d

0:000> g
ModLoad: 00007ffa`b90c0000 00007ffa`b916e000   C:\WINDOWS\System32\ADVAPI32.dll
Breakpoint 0 hit
SomeProc+0xaa9e4:
00007ff7`706aa9e4 4533c9          xor     r9d,r9d

Let’s make a note of where we are currently (stack) so that we have all the interesting locations of SomeProc on the stack (that we might need later …):

0:000> k
 # Child-SP          RetAddr               Call Site
00 00000018`3aafcb88 00007ff7`706aa9df     SomeProc+0xaa9e4
01 00000018`3aafcb90 00007ff7`70694243     SomeProc+0xaa9df
02 00000018`3aafcbc0 00007ff7`70694558     SomeProc+0x94243
03 00000018`3aafcc10 00007ff7`70700f7d     SomeProc+0x94558
04 00000018`3aafcc70 00007ff7`707188c2     SomeProc+0x100f7d
05 00000018`3aaffda0 00007ffa`b8ed26bd     SomeProc+0x1188c2
06 00000018`3aaffde0 00007ffa`ba66dfb8     KERNEL32!BaseThreadInitThunk+0x1d
07 00000018`3aaffe10 00000000`00000000     ntdll!RtlUserThreadStart+0x28

One might think it’s a good idea to open Process Monitor and also monitor Registry activity of the process …

Well, well, well, isn’t this interesting? … =)) Looks like SomeProc is checking (most probably that’s where it is saving it as well – encrypted … thus cryptographic services needed) if the serial/key is saved in the Registry. We can see that it was not found (it does not exist – thus “NAME NOT FOUND” result) which of course makes total sense because I haven’t entered it … it’s in evaluation copy still.

I have narrowed it down to this key because it’s called “snkey” (so it has “key” in its name) which is a pretty big hint + the fact that it was not found (because it’s not entered).

Well … noting down these addresses and setting some breakpoints on them (and others noted before) and continuing investigation …

0:000> bp SomeProc+0xbb4d7
0:000> bp SomeProc+0xbb5ae
0:000> bp SomeProc+0xfe390
0:000> bp SomeProc+0xfed07
0:000> bp SomeProc+0xfe369

I think it’s time to look at these and at the flow in IDA – can’t show you too much there because I would have to censor too much – but so that you can see the tool a little, here it is – point being that it makes a very cool call graph amongst MANY other things and its one of the TOP reverse engineering and malware analysis tools out there:

So, continuing my investigation …

After playing around and analyzing assembly for an eternity … and trying out different places and changing return values on different comparisons and so on … I’ve finally gotten to the correct place (luck was also a big factor of course …) – here we are – this is where I’ve found a good spot to modify the values so that the final check if the application is registered or not, got SUCCESS, hehe …

0:000> g
Breakpoint 4 hit
SomeProc+0xfed07:
00007ff7`706fed07 8ac8            mov     cl,al

0:000> r @al
al=0

0:000> u SomeProc+0xfed07
SomeProc+0xfed07:
00007ff7`706fed07 8ac8            mov     cl,al
00007ff7`706fed09 e81666f7ff      call    SomeProc+0x75324 (00007ff7`70675324)
00007ff7`706fed0e e991150000      jmp     SomeProc+0x1002a4 (00007ff7`707002a4)
00007ff7`706fed13 66443bfe        cmp     r15w,si
00007ff7`706fed17 0f85f9130000    jne     SomeProc+0x100116 (00007ff7`70700116)
00007ff7`706fed1d e89e7afeff      call    SomeProc+0xe67c0 (00007ff7`706e67c0)
00007ff7`706fed22 84c0            test    al,al
00007ff7`706fed24 0f85c1130000    jne     SomeProc+0x1000eb (00007ff7`707000eb)

0:000> r @al = 1

0:000> r @al
al=1

0:000> p
SomeProc+0xfed09:
00007ff7`706fed09 e81666f7ff      call    SomeProc+0x75324 (00007ff7`70675324)

0:000> r @cl
cl=1

0:000> t
SomeProc+0x75324:
00007ff7`70675324 880df6dc1400    mov     byte ptr [SomeProc+0x1c3020 (00007ff7`707c3020)],cl ds:00007ff7`707c3020=00

0:000> db SomeProc+0x1c3020 l1
00007ff7`707c3020  00                                               .

0:000> p
SomeProc+0x7532a:
00007ff7`7067532a c3              ret

0:000> db SomeProc+0x1c3020 l1
00007ff7`707c3020  01

Too bad I cannot show you screenshots of the application and/or of my face now to see the happyness combined with massive tiredness from no sleep =))

At this point as a generic example, the image can be patched so that we skip the instructions that we don’t want to execute (in this simple example – a CMD & JMP) and replace them with a NOP operation (0x90) with any language you like – a simple PowerShell for example:

$bytes  = [System.IO.File]::ReadAllBytes("C:\SomeProc.exe") # full path to image here
# depending on OPCODE sizes that need to be replaced, after finding the correct offset
$offset = 0x12345 # offset of OPCODE where to start
$bytes[$offset]   = 0x90 # patch with 0x90 - NOP operation to skip instruction
$bytes[$offset + 2] = 0x90  # patch with 0x90 - NOP operation to skip instruction
[System.IO.File]::WriteAllBytes("C:\SomeProc.exe", $bytes)

Posted

in

by

Tags: