Adventures in Squeak: Shellcode blob function definitions x64

This was a wild one.

Recently I’ve been deploying my language to create a C2 agent in Squeak called King. This has been an interesting, and very trying process. Since Squeak produces first byte shellcode, if you hit an error or compiler does something weird, the program simply dies. This means that doing a simple mistake, such as typing in an import wrong, can result in a fatal crash with no idea of what caused it aside the error returned by the process (usually the regular 0x05 error for access denied/illegal memory access).


Quick Tangent: Pain Points in low level development.

Kernel32::GetProcAddress()

I have absolutely no idea why but Kernel32::GetProcAddress(“RtlZeroMemory”) sets the error flag PROC_NOT_FOUND despite the fact it exports the symbol for it. This also mapped to 0x0 when ran against a fresh Win10 install on my lab. Wild times.

Kernel32::LoadLibraryA()

Once again, I have no idea why but when mounting ntdll.dll in a process that already has it, a subprocess thread is created that eventually calls some Ldr process exiting the process. That’s what I get for being lazy. Mind, the Microsoft documentation discourages this pattern and states that this kind of behaviour is somewhat expected.


Functions in ShellCode Blobs.

Essentially, when developing a linear sequence of instructions, if one wants to have a ‘function’ to invoke the following pattern is generally observed:

..some code...
label START_FUNCTION:
JMP AFTER_FUNCTION
   <REGISTER OPERATIONS HERE>
   RET
label AFTER_FUNCTION:
..some code..

The start of the function will start with a jump instruction to completely skip over the code, and when it is needed or invoked with a call instruction, the label can be jumped to and the ret before the exit label will return control of the code to the caller.

In x86 Squeak, I handled this with the following instruction to control the label’s location within the blob:

mov REG, LABEL

For some reason, this worked just fine in x86. However, when I started deploying my code as blobs in x64 I started getting weird errors on occasion. A painful 8 hour triage on a Friday night afterwork and a wasted entire Saturday, and the issues dawned on me with my approach:

As any sane engineer can see, this is unideal. The code was moving a statically determined offset from the entrypoint into the register, then storing it for later in a location for later reference. Unfortunately, when I later call this symbol, I am telling the program to jump to the low level address of 0x13A8 which should be an illegal memory location. I have no idea how my code was sometimes functioning up until this point, but it really should have been performing the following instructions:

lea REG, [ rel LABAEL ]

Indeed, if I had of paid attention to NASM’s guidance on this type of referencing, as reproduced below, I’d probably never have had this heartache.


Invoking Functions in ShellCode Blobs

So the other issue I ran into is to do is the order of defining the functions and calling them. Since the above approach only defines the location of the function at the point where the function is compiled, an earlier reference or attempt to invoke the function will result in a crash, since you will likely be performing call 0x0 on uninitialised memory, or jumping to a random DWORD/QWORD location.

This is probably the same reason why the following C code is generally invalid or unaccapted:

void functionB(){
  functionA();
}

void functionA(){
  printf("Hello world");
}

Since at the time functionB invokes functionA, the symbolic reference to functionA may not yet exist; in Squeak this would result in a crash due to accessing illegal memory.

I suppose I might investigate an implementation of writing the function definitions at the start of the Squeak binary and ‘linking’ them ahead of time. Who knows.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Secured By miniOrange