2

Recently I've been working on a project. The main purpose of the project is to generated statically undetectable PE samples. Where each time one generates a PE sample, each generated sample is going to be significantly different than the previous one. I'll be using shikata_ga_nai (https://github.com/rapid7/metasploit-framework/blob/master/modules/encoders/x86/shikata_ga_nai.rb) to achieve polymorphism. However I'm currently working to improve on garbage assembly generation. There are a lot of possibilities to create garbage assembly. However most of the encoders, including shikata_ga_nai generate garbage assembly at a fixed relative position - meaning the garbage instructions are placed at the end of the code or the beginning. Is there anyway to scatter these garbage instructions across the code WITHOUT messing up the conditional/unconditial jmp and call instructions with relative offsets?

For the sake of simplicity take the below piece of assembly as an example of a code that my PE file is going to execute

Payload

0x42:   0F B7 2C 17             movzx   ebp, word ptr [rdi + rdx]
0x46:   8D 52 02                lea     edx, [rdx + 2]
0x49:   AD                      lodsd   eax, dword ptr [rsi]
0x4a:   81 3C 07 57 69 6E 45    cmp     dword ptr [rdi + rax], 0x456e6957
0x51:   75 EF                   jne     0x42

Let's say the garbage instruction I want to insert is cmovne rsi, rsi. If I insert this instruction at the beginning or the end of the code the logic of it doesn't change.

However If I insert cmovne rsi, rsi before the cmp instruction the 0x4a offset, when the conditional jmp instruction at the 0x55 will execute, it's going to skip the instructions located at 0x42-> 0x42: movzx ebp, word ptr [rdi + rdx] and start executing at address 0x46 -> lea edx, [rdx + 2] becase the offset it's trying to jmp is relative to the rip.

(Old offset -> 0x42+ garbage instruction length -> 0x4= New WRONG offset -> 0x46 )

Garbage padded payload

0x42:   0F B7 2C 17             movzx   ebp, word ptr [rdi + rdx]
0x46:   8D 52 02                lea     edx, [rdx + 2]
0x49:   AD                      lodsd   eax, dword ptr [rsi]
0x4a:   48 0F 45 F6             cmovne  rsi, rsi
0x4e:   81 3C 07 57 69 6E 45    cmp     dword ptr [rdi + rax], 0x456e6957
0x55:   75 EF                   jne     0x46

Is there any approach I can take to resolve this?

4
  • There's no simple solution. But it sounds like XY problem. I see no benefits you can get inserting NOP in the middle of code shifting all instructions. Commented Nov 3, 2020 at 12:13
  • It's not just the nops. The example I gave here was for the sake of simplicity. Final product will have subroutines in them that doesn't have any effect the course of the program but is random enough to confuse the EDR/AV that implements static detection. Commented Nov 3, 2020 at 14:36
  • Also there's a clear problem here at least for me. The problem is the offsets get shifted during instruction insertion. All I'm doing is asking for the solution. I don't have any idea how to overcome this issue. Also any alternatives are welcome. Commented Nov 3, 2020 at 14:38
  • No, I don't say that problem doesn't exist, I understand it, but implementing universal solution would take a while, that's why common way to inject code into existing subroutine is replacing current instructions with branch to initialized memory where code of injection written. Commented Nov 3, 2020 at 14:46

1 Answer 1

2

Assemblers are faced with a similar problem: the user writes textual labels such as @loop, and references them in conditional branch instructions such as jbe @loop. However, the assembler does not know ahead of time how far the branch is from the label (in order to generate the displacement for the branch). It only learns that after generating machine code for the rest of the instructions.

What to do about this? Re-introduce symbolic labels. Instead of representing the jne as jne 0x42 -- which has the address directly inside of it -- represent it as jne top_of_loop. Then, after you've added garbage instructions, compute the length from the jne to top_of_loop.

2
  • The jne 0x42 instruction is placed there beforehand. I don't have any control over code that's already been compiled. But if I understood correctly with your suggestion I can locate the jmps before adding the garbage assembly, replace their hardcoded values with labels, add garbage assembly and finally assemble the whole code into garbage-infused new equally functional code? Commented Nov 3, 2020 at 20:23
  • Roughly, yes. Locating the jumps might require actual disassembly because the bytes that denote a conditional or unconditional jump might also appear in the middle of other instructions. But, yes, if you keep track of how far a jump is away from its destination, you can change the relative displacement value in its encoding if it gets closer or further away. Commented Nov 3, 2020 at 20:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.