Aight
Idea: Disassembler Obliterator
Concept
So the idea is pretty simple.
The point of this is to break the disassembler, not confuse the user.
Disassemblers work really well because they can parse whatever they're given, so the idea is to give it something it can't make sense of.
That will fuck up instruction size calculation, as well as whatever else, causing the disassembler to completely fail, and break for both valid and invalid instructions.
There are a lot of invalid opcodes out there, so this should be simple enough.
Getting to it
So I've made a test program with a little bit of trash code in the middle:
The plan is to replace this code with random hexadecimal, as many times as needed to complitely obliterate IDA.
Now IDA isn't particularly difficult to break I feel. If I'm not mistaken, a couple nops easily mess it up, but it's a good starting point.
The disassembly looks like this:
(ye ik my theme is shit, I'll change it eventually)
So as we can see, we have that first code condition (
Besides that, all we would really have to do is shuffle sume bits around between that jump and the
So, changing the jump isn't hard, we just notice that it's a 0x75 jump, which is a short (8 bit) jump.
(from here)
So if that's the case, we need the opcode for the relative 8bit jmp:
(from here)
So now we get the file offset:
And change that byte in your hex editor of choice:
turns to
And if we reload it into IDA, we can now see that we have a jump:
So all that's left really, is just to fill everything between that jump and the label (40104C - 40106B) with trash (Imma start with
(better save the address of the function:
turns to
Fuck.
Well, it would seem that IDA's a bit smarter than that.
Cheat engine is having a bit of a harder time, but still manages to get the main part of the function.
Random.
Results with random values aren't much better. I figure because of the jump. The jump basically tells the disassembler where the valid code resumes.
JNZ.
Jnz yields somewhat better results, with IDA not recognizing the block of code as a subroutine (even though there's a call to it).
Can be useful, specially because it's still possible to make an impossible condition and might be a bit more confusing.
No Jumps.
Same as with JNZ.
Aftermath
The main problem with this was that disassemblers, when given instructions that technically don't exist (which is the case with ``FF FF``), will automatically assume it's data and move on trying to find valid instructions.
For this reason, spamming random hex or invalid instructions into code doesn't seem to be of much help.
With that said, a polymorphic engine might be in order.
Using what was learned here, and the idea of a polymorphic engine, a program where IDA wouldn't have anything in the functions window might be possible.
This "code caving" strategy might be useful for more than that. The same way we can deprive the reverser from information, we could also do the oposite. Make a binary so cluttered with xrefs it would be impossible to do anything, with little performance hit.
Plus, this can be a cheap and easy strategy to evade more basic detection systems that may rely on for example hashes to determine whether or not a certain binary is "blacklisted" or whatever. No fancy stuff, just change a predefined/hardcoded set of bytes in a binary, and it's invisibru.
Fin
Sorry no great discoveries were made here today, but hope you had fun nonetheless, I know I did.
L8r.
So the idea is pretty simple.
The point of this is to break the disassembler, not confuse the user.
Disassemblers work really well because they can parse whatever they're given, so the idea is to give it something it can't make sense of.
That will fuck up instruction size calculation, as well as whatever else, causing the disassembler to completely fail, and break for both valid and invalid instructions.
There are a lot of invalid opcodes out there, so this should be simple enough.
Getting to it
So I've made a test program with a little bit of trash code in the middle:
The plan is to replace this code with random hexadecimal, as many times as needed to complitely obliterate IDA.
Now IDA isn't particularly difficult to break I feel. If I'm not mistaken, a couple nops easily mess it up, but it's a good starting point.
The disassembly looks like this:
(ye ik my theme is shit, I'll change it eventually)
So as we can see, we have that first code condition (
!(*str & 0x7F)
) at .text:104A, it would come in handy to change that to an unconditional jump (I would have made an impossible condition in code, but msvc optimization for release is just insane).Besides that, all we would really have to do is shuffle sume bits around between that jump and the
after_trash
label, and we should be good to go.So, changing the jump isn't hard, we just notice that it's a 0x75 jump, which is a short (8 bit) jump.
(from here)
So if that's the case, we need the opcode for the relative 8bit jmp:
(from here)
So now we get the file offset:
And change that byte in your hex editor of choice:
turns to
And if we reload it into IDA, we can now see that we have a jump:
So all that's left really, is just to fill everything between that jump and the label (40104C - 40106B) with trash (Imma start with
FF
s).(better save the address of the function:
0x401040
)turns to
Fuck.
Well, it would seem that IDA's a bit smarter than that.
Cheat engine is having a bit of a harder time, but still manages to get the main part of the function.
Random.
Results with random values aren't much better. I figure because of the jump. The jump basically tells the disassembler where the valid code resumes.
JNZ.
Jnz yields somewhat better results, with IDA not recognizing the block of code as a subroutine (even though there's a call to it).
Can be useful, specially because it's still possible to make an impossible condition and might be a bit more confusing.
No Jumps.
Same as with JNZ.
Aftermath
The main problem with this was that disassemblers, when given instructions that technically don't exist (which is the case with ``FF FF``), will automatically assume it's data and move on trying to find valid instructions.
For this reason, spamming random hex or invalid instructions into code doesn't seem to be of much help.
With that said, a polymorphic engine might be in order.
Using what was learned here, and the idea of a polymorphic engine, a program where IDA wouldn't have anything in the functions window might be possible.
This "code caving" strategy might be useful for more than that. The same way we can deprive the reverser from information, we could also do the oposite. Make a binary so cluttered with xrefs it would be impossible to do anything, with little performance hit.
Plus, this can be a cheap and easy strategy to evade more basic detection systems that may rely on for example hashes to determine whether or not a certain binary is "blacklisted" or whatever. No fancy stuff, just change a predefined/hardcoded set of bytes in a binary, and it's invisibru.
Fin
Sorry no great discoveries were made here today, but hope you had fun nonetheless, I know I did.
L8r.