forked from 0xZ0F/Z0FCourse_ReverseEngineering
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
96 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,102 @@ | ||
# 8.04 Get Element | ||
# 8.04 Get Element - WIP | ||
Now let's look at a function that has to do with looking data up in the table. Remember, it doesn't matter which functions we reverse first. I'm choosing based on what I think will be a good order to go in. | ||
|
||
There are multiple functions that might get something from the table: `RtlEnumerateGenericTable`, `RtlGetElementGenericTable`, `RtlLookupElementGenericTable`, and some others. Based on the names, I think `RtlGetElementGenericTable` or `RtlLookupElementGenericTable` will be the easiest. Out of those two I'd guess `RtlGetElementGenericTable` will be the simplest. I'd guess that it simply looks in the table at the index passed to the function. This is just a guess, I don't even know what parameters it takes yet. | ||
|
||
Disassembly of `RtlGetElementGenericTable`: | ||
```asm | ||
00007FF8BBD1C1C9 JE ntdll.7FF8BBD1C21C | ||
00007FF8BBD1C1CB MOV EAX, DWORD PTR DS:[RCX+0x24] | ||
00007FF8BBD1C1CE CMP R11D, EAX | ||
00007FF8BBD1C1D1 JA ntdll.7FF8BBD1C21C | ||
00007FF8BBD1C1D3 CMP R11D, R10D | ||
00007FF8BBD1C1D6 JE ntdll.7FF8BBD1C200 | ||
00007FF8BBD1C1D8 JB ntdll.7FF8BBD66C7A | ||
00007FF8BBD1C1DE SUB EAX, R11D | ||
00007FF8BBD1C1E1 MOV EDX, R11D | ||
00007FF8BBD1C1E4 SUB EDX, R10D | ||
00007FF8BBD1C1E7 INC EAX | ||
00007FF8BBD1C1E9 CMP EDX, EAX | ||
00007FF8BBD1C1EB JA ntdll.7FF8BBD1C20A | ||
00007FF8BBD1C1ED TEST EDX, EDX | ||
00007FF8BBD1C1EF JE ntdll.7FF8BBD1C1F8 | ||
00007FF8BBD1C1F1 MOV R8, QWORD PTR DS:[R8] | ||
00007FF8BBD1C1F4 ADD EDX, EBX | ||
00007FF8BBD1C1F6 JNE ntdll.7FF8BBD1C1F1 | ||
00007FF8BBD1C1F8 MOV QWORD PTR DS:[RCX+0x18], R8 | ||
00007FF8BBD1C1FC MOV DWORD PTR DS:[RCX+0x20], R11D | ||
00007FF8BBD1C200 LEA RAX, QWORD PTR DS:[R8+0x10] | ||
00007FF8BBD1C204 MOV RBX, QWORD PTR SS:[RSP+0x8] | ||
00007FF8BBD1C209 RET | ||
00007FF8BBD1C20A LEA R8, QWORD PTR DS:[RCX+0x8] | ||
00007FF8BBD1C20E TEST EAX, EAX | ||
00007FF8BBD1C210 JE ntdll.7FF8BBD1C1F8 | ||
00007FF8BBD1C212 MOV R8, QWORD PTR DS:[R8+0x8] | ||
00007FF8BBD1C216 ADD EAX, EBX | ||
00007FF8BBD1C218 JE ntdll.7FF8BBD1C1F8 | ||
00007FF8BBD1C21A JMP ntdll.7FF8BBD1C212 | ||
00007FF8BBD1C21C XOR EAX, EAX | ||
00007FF8BBD1C21E JMP ntdll.7FF8BBD1C204 | ||
7FF8BBD1C1B0 MOV QWORD PTR SS:[RSP+0x8], RBX | ||
7FF8BBD1C1B5 MOV R10D, DWORD PTR DS:[RCX+0x20] | ||
7FF8BBD1C1B9 LEA R11D, QWORD PTR DS:[RDX+0x1] | ||
7FF8BBD1C1BD MOV R8, QWORD PTR DS:[RCX+0x18] | ||
7FF8BBD1C1C1 OR EBX, 0xFFFFFFFF | ||
7FF8BBD1C1C4 MOV R9D, R11D | ||
7FF8BBD1C1C7 CMP EDX, EBX | ||
7FF8BBD1C1C9 JE ntdll.7FF8BBD1C21C | ||
7FF8BBD1C1CB MOV EAX, DWORD PTR DS:[RCX+0x24] | ||
7FF8BBD1C1CE CMP R11D, EAX | ||
7FF8BBD1C1D1 JA ntdll.7FF8BBD1C21C | ||
7FF8BBD1C1D3 CMP R11D, R10D | ||
7FF8BBD1C1D6 JE ntdll.7FF8BBD1C200 | ||
7FF8BBD1C1D8 JB ntdll.7FF8BBD66C7A | ||
7FF8BBD1C1DE SUB EAX, R11D | ||
7FF8BBD1C1E1 MOV EDX, R11D | ||
7FF8BBD1C1E4 SUB EDX, R10D | ||
7FF8BBD1C1E7 INC EAX | ||
7FF8BBD1C1E9 CMP EDX, EAX | ||
7FF8BBD1C1EB JA ntdll.7FF8BBD1C20A | ||
7FF8BBD1C1ED TEST EDX, EDX | ||
7FF8BBD1C1EF JE ntdll.7FF8BBD1C1F8 | ||
7FF8BBD1C1F1 MOV R8, QWORD PTR DS:[R8] | ||
7FF8BBD1C1F4 ADD EDX, EBX | ||
7FF8BBD1C1F6 JNE ntdll.7FF8BBD1C1F1 | ||
7FF8BBD1C1F8 MOV QWORD PTR DS:[RCX+0x18], R8 | ||
7FF8BBD1C1FC MOV DWORD PTR DS:[RCX+0x20], R11D | ||
7FF8BBD1C200 LEA RAX, QWORD PTR DS:[R8+0x10] | ||
7FF8BBD1C204 MOV RBX, QWORD PTR SS:[RSP+0x8] | ||
7FF8BBD1C209 RET | ||
7FF8BBD1C20A LEA R8, QWORD PTR DS:[RCX+0x8] | ||
7FF8BBD1C20E TEST EAX, EAX | ||
7FF8BBD1C210 JE ntdll.7FF8BBD1C1F8 | ||
7FF8BBD1C212 MOV R8, QWORD PTR DS:[R8+0x8] | ||
7FF8BBD1C216 ADD EAX, EBX | ||
7FF8BBD1C218 JE ntdll.7FF8BBD1C1F8 | ||
7FF8BBD1C21A JMP ntdll.7FF8BBD1C212 | ||
7FF8BBD1C21C XOR EAX, EAX | ||
7FF8BBD1C21E JMP ntdll.7FF8BBD1C204 | ||
``` | ||
|
||
This function is clearly going to be more of a challenge than the others. | ||
|
||
### General Overview | ||
When a function is pretty involved, I always like going through it and identifying the obvious stuff, then going back through and analyzing more closely. The first thing we'll do is check for function parameters. | ||
* RCX is used like a data structure (`MOV EAX, DWORD PTR DS:[RCX+0x24]`), so it's probably the table. | ||
* RDX is also used, but with an offset of +0x1 (`LEA R11D, QWORD PTR DS:[RDX+0x1]`). RDX is probably not a data structure, maybe a pointer, we'll figure that out later. Just note that RDX is used. | ||
* R8 and R9 are overwritten, so they were probably not parameters. | ||
Now we know that this function only takes 2 parameters. The first one being the table, the second one is only a guess but it could be an index into the table. That quick analysis is going to make things easier, but let's keep looking around. | ||
|
||
* | ||
Something I like doing is identifying loops. Just by scanning this function I can tell it's very likely there is a loop because of the `JMP ntdl.###` instructions. | ||
|
||
The first set of jumps are `JCC ntdll.7FF8BBD1C21C`. `ntdll.7FF8BBD1C21C` zeroes EAX, then jumps to `ntdll.7FF8BBD1C204` which does something to RBX then returns. This is probably because of a condition "failing", so we'll keep that in mind. I say this is may be a fail condition because it's early on in the function and it jumps immediately to a `ret`. Also the return value is set to 0. | ||
|
||
There is some other mildly interesting jumps but nothing to note. We'll just examine those when we get there. With that said, I think this is a good time to get started with the full analysis. | ||
|
||
>If you don't already, I'd highly recommend writing notes and/or pseudo code as you are reverse engineering. | ||
# Part 1 | ||
|
||
Let's focus on the following code: | ||
```asm | ||
MOV QWORD PTR SS:[RSP+0x8], RBX | ||
MOV R10D, DWORD PTR DS:[RCX+0x20] | ||
LEA R11D, QWORD PTR DS:[RDX+0x1] | ||
MOV R8, QWORD PTR DS:[RCX+0x18] | ||
OR EBX, 0xFFFFFFFF | ||
MOV R9D, R11D | ||
CMP EDX, EBX | ||
JE ntdll.7FF8BBD1C21C | ||
MOV EAX, DWORD PTR DS:[RCX+0x24] | ||
CMP R11D, EAX | ||
JA ntdll.7FF8BBD1C21C | ||
``` | ||
* RBX is preserved/saved on the stack. | ||
* Member4 of the table is moved into R10D. | ||
* `LEA R11D, QWORD PTR DS:[RDX+0x1]` is a very important instruction. It's essentially `R11D = RDX + 1`. This might be done instead of using the `INC` instruction to preserve the value of RDX. | ||
* Next, the fourth member of the table is moved into R8. | ||
* `OR EBX, 0xFFFFFFFF` sets EBX to -1. | ||
* R11D (RDX + 1) is moved into R9D. | ||
* EDX (second parameter) is then compared to EBX (-1). This tells us a few things. First, we can be even more sure that EDX is an index. Also, previously the NumberOfElements member in the table data structure was accessed with the offset of +0x24 in `RtlNumberGenericTableElements`. You would expect it to be accessed with the offset of +0x20 because it's the fifth member. The fact that EDX is used instead of RBX could mean that the fifth parameter is not 8 bytes, instead it's only 4 bytes. We still can't be certain, but it's nice to know that it's less likely that we're wrong. | ||
* If EDX (the second parameter) is -1, then jump to `ntdll.7FF8BBD1C21C` which is the fail condition. | ||
* `MOV EAX, DWORD PTR DS:[RCX+0x24]` moves the NumberOfElements member into EAX. | ||
* R11D (RDX + 1) is then checked if it's greater than EAX (NumberOfElements). This is bounds checking to make sure the index isn't greater than the range of the table. This also tells us another piece of useful information, the index is zero-based. This means it starts from index zero, not 1, similar to a conventional array. This makes sense because the number of elements is *not* zero-based (0 elements would mean it's empty). Again, this is just like an array. | ||
* If R11D is greater than EAX, then it jumps to the fail condition. Here is a pro tip, pay attention to the jump types. `JA` tells us that it's unsigned. | ||
|
||
Here is some pseudo code to ease your mind: | ||
```c | ||
ULONG adjustedIndex = index + 1; | ||
if(index == -1 || adjustedIndex > Table->NumberOfElements){ | ||
return 0; | ||
} | ||
``` | ||
|
||
# Part 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters