I found this post by Alex Ionescu pretty interesting. I recreated the poc and wrote position independent shellcode. It’s more like executing shellcode directly by the windows loader.
One could develop complete malware by dynamically locating the base address of kernel32.dll and once you locate the functions LoadLibraryA and GetProcAddress, you can load any library in the system and find the exported symbols, in which you have complete access to the win32 API.
You don’t need to specifically write position independent code using assembly. You can directly code in C/C++ and extract the opcodes.
For example using the ‘InMemoryOrderModuleList’ LDR_DATA_TABLE_ENTRY located in the PEB->LDR we can get the base address of kernel32.dll. Usually kernel32.dll can be found in the third LDR_MODULE in the double linked list. If you have done shellcoding under Windows these things should be familiar.
Name:
((PLDR_DATA_TABLE_ENTRY)Peb->Ldr->InMemoryOrderModuleList.Flink->Flink->Flink)->FullDllName.Buffer
Address of kernel32.dll:
((PLDR_DATA_TABLE_.ENTRY)Peb->Ldr->InMemoryOrderModuleList.Flink->Flink->Flink)->Reserved2[0]The following are in .bz2 archives. This method will only work starting from Windows 8 and upwards. I have tested the following on Windows 8, 8.1, 10 64-bit platforms. On the first run you might encounter an exception 0xc0000005. On the second run the code should execute.
CreateProcess calc.exe 32-bit POC (268 bytes)
QlpoOTFBWSZTWTfQabcAACv/3/zcAExEBGwFyoZYkC9Emt3gKAAAoAARgACqECAQ BqAAlBFNqmgDQAA0aAAMTR6T01HqPSbaoNU8qepoAAPUAAAABgAAISVD8TqqtEgA Mu01AggpY0emcMiU3cG+s8g65BfcYBsGBxMcyfLzk65IObfzU25rNK+7gaEjUYIv EaESpoPFJB2RW9z47KcotA73EDpiILQW1MhhVfyTEur86L/EsGGAOAzGDkxr6+Tf 8XckU4UJA30Gm3A=
WinExec calc.exe 64-bit POC (268 bytes)
QlpoOTFBWSZTWUlqbYYAAC9/+/ycwMTE5FQEQkJUtG51BwEhDgAgAAMAgASAAACA gaAAdCJQGhoaAAAwBk0DQ0yGgamlPKAAAANAMAAAARyJEUNN6+kgAPvc5gggbwbP m0ek9kHSQUIDnB/UP1fH7GCwemE0VCqH8HSl14qTQl9jJzRwNv/+Jp851qzr2E8s HQuBcQuyGgUBLkZRVwKyGtstvUoV+Au5IpwoSCS1NsMA
Scroll.exe 32-bit (1000 bytes)
QlpoOTFBWSZTWdH4AksAAJP////fzF5UiXws52/vv6b9f2ZuegGOJJMEpfm9/d3V XGfVoAHVUhAhIFNqeoZA00DQGQBoNDQDQAaADQGgNAAaaDJoZNDTINNMaj0mg1PU E0m1JspDR6j9SeKZHomyEPRAyNND1AyAGgGQBoA9QBoNADQNGh6h+lF0SriljnmF CEXWAkIYUBzU2IdWtH5mY1phXtLUT9bF1peRix6XNfmmWYbP805OKa67btD1yg+g 22oTFGMyvtO+2lTX6K08QV0JRRAIIkKHRwlZYKiCmFQJARaIIGgFs3O4F8xFY3u1 8Ed/Ly9EmKju+PQs1xJGTDYQUP2prw3YEveIXBphu+uU1q3TVSIy89nCQm8t3EoJ 4Nex6hCZzTZID+MCpd5FO/Iru+dGlzcFo1ONtsoIDCJZAeJJuJvOvErHuLwIi+Nl dP3Me5CTEBmUJwx6sbwq5vb0mLcSb4BEQgppcRnHtViyGDlct1PqrCgoSNwV1RwM mfGKThy5TsOg4KedXg4gRDjkywjEXSYb1VKGA27kKuMhY1E6QQoj1zYs1FPdNrfG j4FNeIKAMeOr76le1TFt8liZChbq9PWNJCp4SB1YXs7WFq1hQTL3SpzLFVcSxq/+ J+nPgtVILEb70lqw+p+8tglc5iZmSb6Y5r6XEWS0oAUkhxpC1R3wEqGwkmLSjXFI pO6u8ikgAlD0KNOxEw0vH9snlTX9Y37tsPMCGODKPClN/i2U+NDXYxyf93lrysnk TLY2t9yV4lfeKcmCTuWIav9mw1MfBUJBQEpsiewuzKUqVeLWhYm6bDt57A5z8p1Q vZhgIfE9LSLtaW3I7orYiZFAYdrOnVVhkoKshATbrQJlihH/xdyRThQkNH4AksA=
If we have a look at the PE structure we can see that our position independent code starts from the Data Directory array which is overwritten by our code.
pimageoptionalheader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = 64db3100 pimageoptionalheader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = 8b307b8b
This PE will have no sections and there will be no imports to be found since everything is dynamic. We are overwriting the Data Directory array with our code, thus some tools will fail to analyze this PE. This technique might be used as an anti-debugging method. Tools like IDA will crash while loading this PE since this PE is corrupt.
There’s a possibility of making your code undectable This is the anti-virus scan results.