Visual studio 2019 solution to generate Position Intependent Code using C. Fast and easy development without that pesky ASM! Code and settings are heavily based on @mattifestation repo https://github.com/mattifestation/PIC_Bindshell.
The solution comes with three projects:
- ProcFinder
- ShellcodeRunner
- ShellcodeDebugger
Solution also has a few helper scripts that are utilized during the build process.
Attention, read the following or your life will be hard and full of misery! Read the code comments, they explain what is going on and suggest different ways to achieve the same thing in different ways so you can choose the best approach for your goals!
ProcFinder is a demo code that will generate a shellcode that is automatically updated in the ShellcodeRunner project. The code will find the GetProcAddress function address from PEB automatically, as well as the Kernel32.dll module handle. After that we can utilize WIN32 functions in a normal manner using your own GetProcAddress function. In this example, we will run GetNativeSystemInfo and return its output.
In order to generate truly Position Intependent Code, you must keep few restrictions in mind. You must not use strings in your code! Those would normally be stored in the .data segment of the PE file, and thus are not in the .text segment that is used to generate the shellcode! Read-Only variables, such as strings and arrays might endup to .rdata segment, these can still be done by merging .rdata to .text segment, but this will result to a situation where offset must be used to execute the shellcode. You can also declare the variable to be stored directly to the .text segment by using __declspec(allocate(".text")), but this will result into use of offsets as well. Only way to store text without resorting to offsets that I was able to find was to use char arrays, with limitation of maximum of 15 elements per array.
Another thing to keep in mind is that when you declare new functions to the code, you must update the FunctionLinkOrder.txt in the project directory to tell the linker not to place other functions before the entrypoint in the .text section to keep the shellcode to work without using offsets.
Note that if you wish to use functions from User32.dll, you must first load the DLL and then use GetProcAddress like you would normally.
The example code will contain explanations for each step in the code comments.
Building the project will automatically run a powershell command to update the shellcode.h contents in the ShellcodeRunner project. The exact command is:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File
Do note that this has been only tested in x64! Also the release setting has only the correct configuration! Do not even try the debug config.
ShellcodeRunner project is a simple project to run the shellcode generated by the ProcFinder. Contents of the Shellcode.h are updated automatically when you build the ProcFinder project, so only thing you might need to update before building is the offset. Just copy and paste the output from the ProcFinder build console to variable: FUNCTION_OFFSET in the ShellcodeRunner project.
Obviously there is no much option to debug the code when its executed like that, that is why there is also a third project in the solution.
Super simple C project that has roughly the same code as the ProcFinder project. Copy and paste code from ProcFinder here to debug it. This is also only project that supports the Debug configuration, for obvious reasons.
Git repo comes with Visual Studio project template. Simply unzip the contents of ShellcodeTemplate.zip to %userprofile%\Documents\Visual Studio 2019\Templates\ProjectTemplates
After that restart Visual Studio, open this solution, right click solution -> Add -> New Project... And search for ShellcodeTemplate. Only thing you need to keep in mind is to create new (or copy from another project) the FunctionLinkOrder.txt, as that is not part of the template.
And thats it! Building your new project will also update the ShellcodeRunner project shellcode, and will output the function offset as well!
Use CFF Explorer, or similar tool to check that all your variables are in the .text section as you intended!
- Only tested in x64
- Will contain /x00
- Likely much more...