All posts by Skizo

RFC 7233: So Wrong

Do you remember that one time (about 10 minutes ago) where I started double-checking RFC 7233 to make sure I was doing everything perfectly, and found out that the RFC is WRONG? There’s a first time for everything.

HTTP/1.1 206 Partial Content
Date: Wed, 15 Nov 1995 06:25:24 GMT
Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT
Content-Length: 1741
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES

--THIS_STRING_SEPARATES
Content-Type: application/pdf
Content-Range: bytes 500-999/8000

...the first range...
--THIS_STRING_SEPARATES
Content-Type: application/pdf
Content-Range: bytes 7000-7999/8000

...the second range
--THIS_STRING_SEPARATES--

After deep analysis (and lots of recalculations) I discovered that the RFC is incorrect and uses a wrong content length. Let’s sum it up:

  1. 500 (500-999) + 1000 (7000-7999) bytes of pure content
  2. 197 bytes of multipart boundaries and headers
  3. 11 CR+LF (22 bytes)

For a whopping total of 1719. What’s left? 22 bytes. Or, maybe best put, 11 CR+LF. They counted them twice.

Bonus fact: this multipart example is also INVALID and might be rejected from strict clients. A leading CR+LF is considered part of the boundary, so the first boundary in the content should be separated by three CR+LF and not two.

Array Initialization & Split() Bug. Solution born from a WTF?!?

Everybody faced problems with array initialization, error handling for dinamics and so on. Today, first time in my life (and that’s almost 20 year worth of coding) I found a bug out of the blue. Or what I think to be so. Typical example incoming:

On Local Error Resume Next
Dim sArray() As String, C As Long, D As Long

D = [102 or 99]
For C = 100 To D
	ReDim sArray(UBound(sArray) + 1)
	If Err.Number > 0 Then
		ReDim sArray(0)
		Err.Clear
	End If
	sArray(UBound(sArray)) = CStr(C)
Next
Debug.Print UBound(sArray)
On Local Error GoTo 0

' D = 102 — Ubound(sArray) = 2
' D = 99  — UBound(sArray) = Error

This example is stupid on purpose, but gets us to the point. If D is set to 99, then sArray is gonna be uninitialized. Which means that we have to set another error handling to check wether or not the array contains something. And this generally brings us pain, it’s always very, very, very ugly to do, but until now it was the only way, aside setting up a base 0 array with data starting from 1, like this:

ReDim sArray(0) As String
ReDim sArray(UBound(sArray) + 1)

sArray(UBound(sArray)) = 1
For C = 1 To UBound(sArray)
	Debug.Print sArray(C)
Next

Another ugly way to do the job, but as I said a little above, there weren’t many ways to do it. Until I found something so stupid to be genial. Let’s see a slightly modified version of the same code.

Dim sArray() As String, C As Long, D As Long
sArray = Split(""," ")

D = [102 or 99]
For C = 100 To D
	ReDim sArray(UBound(sArray) + 1)
	sArray(UBound(sArray)) = CStr(C)
Next
Debug.Print UBound(sArray)

' D = 102 — Ubound(sArray) = 2
' D = 99  — UBound(sArray) = -1

You probably won’t understand that, so I’ll explain: the Split() of a 0 length string with a non-0 length string, brings us an amazing Array(0 To -1). You heard it right, 0 to -1. What does this mean?

  1. Empty arrays can checked with a (UBound(Array) = -1).
  2. Incremental arrays available from scratch, from index 0.
  3. Possibility to return safely arrays without the need to define a count variable to set the array lenght.
  4. Profit!

This is one of the most stupid amazing things I ever seen, and it caught me so off-guard I totally didn’t expect it. Could even make it to The Daily WTF?!?

SEH Jump

A little intro before the code. It is possible, working the way through a SEH, to jump to another location instead of using a standard JMP. The advantage of this is the (eventual) obfuscation of the jump (if done properly), and although I’ve seen plenty of references around the web, I just couldn’t find anything on this matter, especially in the way I wanted it.

What you are going to find about SEH around the web (including dirty tricks) are most likely:

  1. Standard way (no tricks at all, just standard behaviour)
  2. Jump & Clean (jump to the SEH, never get back)
  3. Clean jump based on SEH hack (only here, searched a lot, and never found)

About #1, I will let you seek through the vast ASM/C++ references, no need to talk about it here.

About #2, code snippet:

.code
assume fs:nothing

start:
push @@SEH_Handler   ; Address of SEH
push FS:[0]          ; Original SEH
mov FS:[0], ESP      ; Install SEH
xor eax, eax
idiv eax             ; Generate exception
int 3                ; Will never reach this
jmp @@Exit

@@SEH_Handler:
mov esp, [esp+8]     ; Restore pre-jump stack
pop FS:[0]           ; Reset Original Handler
add esp, 4           ; Remove SEH address from stack
[...]                ; Code goes on as normal

This code works perfectly. But there’s a pretty grievous problem with it. That is, it assumes and requires that you are the author of both codes (pre and post jump) and that you can modify them. Which wasn’t my case.

Example: while writing a packer, or a loader, or whatever you may want to, you just can’t clean SEH handler and the stack after the jump. Because, since the code isn’t yours and can’t be recoded, it won’t do it. And that’s bad. Imagine it doesn’t have an exception handler, and at every unhandled exception it “returns” to your OEP. Nasty, huh? And that’s the least of the problems actually.

Nastier problem is having a “dirty” stack, and god only knows what else could happen. But there is a workaround, which is cleaning and resetting everything inside the SEH handler, with a bit of hacking and eventually some heuristic approach. At least mine had to be, I knew nothing about it.

.code
assume fs:nothing

start:
push @@SEH_Handler          ; Address of SEH
push FS:[0]                 ; Original SEH
mov FS:[0], ESP             ; Install SEH
xor eax, eax
idiv eax                    ; Generate exception
int 3                       ; Will never reach this
jmp @@Exit

@@SEH_Handler:
mov eax, [esp+C]            ; Pointer to SEH Data
add [eax+C4], 8             ; [1]
mov [eax+B8], @@JustGoOn    ; [2]
mov eax, [esp+8]
mov eax, [eax]              ; Pointer to original Stack
mov FS:[0], eax             ; Reset Original Handler
xor eax, eax                ; Set to 0 to "return"
ret

; [ ESP+C ]: SEH_Data
; [ SEH_Data + C4 ]: Original Stack Address (pre-jump)
; [ SEH_DATA + B8 ]: Return Point

Pointer to SEH data ([ESP+C]) points to a zone in the stack with lots of info, including hardware breakpoints and (between the other things) the exact stack address returned to you after the jump. And, of course, the address it will return to.
Adding 8 in point [1] makes the kernel return to the address with the stack pointer set to the original one (pre-jump) minus the two push instructions (first two instructions after the start:). Which also basically means, it will return from the SEH handler with the original stack pointer, just as if the code started from the return point.

The point [2] should be fairly readable and intuitive: hacks the stack to “hack” the return point. Another approach, in case you wanted to continue right from the next instruction, would have been to add the size of the operand to the address (in this case the size of IDIV EAX). Just to remind you, the default SEH way is to return to the very same instruction that caused the exception.

With this piece of code you achieve two things: the first and most important, you perfectly and seamlessly jump from one context to another, just as if there were two programs in the same executable; secondly you have the ability to easily obfuscate the jump, which in this case is pretty obvious, but that’s up to you, not me.