Copy Link
Add to Bookmark
Report
Xine - issue #5 - Phile 104
Ú-----------------------------¿
| Xine - issue #5 - Phile 104 |
À-----------------------------Ù
The darkener philosophy...
--------------------------
"The best way for war leaders to be unpredictable
is to decide with dice..."
"To defeat your ennemy, you must understand him..."
! Intro :
I think sad that most virii released in the wild are destinated to an end...
Everything must finish some say. The only way would you say for a virus
for not being added to AVP bases is to remains hidden from the world, so
inactive :( Or, better, to select the files to infect; but AVers did always
smooth that problem. What I should do, is to make my virus a black box,
something that only I understand...
If an AVer open an infected file and see "cmp [...],'EP'", he will
understand directly; some new virusses make "... ,'EP' xor MyNumber",
it's better, but always spottable. The way to hide it should be then to
crypt it, so that instructions must be decrypted b4 analysis; better
but always solvable. If it is crypted, there always remains some possibility
to copy your decrypt routine and to execute it on the raw-virus and then
search that decrypted one. It's time to make AVers' life harder.
! viva poly :
If you make some polymorphic engine, something that creates a crypt/decrypt
routine, randomly, randoms numbers will be generated with a 'seed', so
the same 'seed' give the same random numbers - and the same crypt/decrypt
routines. The way should be then, when you infect :
create a crypter routine (cA) with SeedA
crypt your virus (without poly engine) with cA
create a crypter and decrypter (cB & dB) routine with SeedB
encrypt the poly engine with cB
write in infected file:
dB
crypted poly
SeedA
crypted vir
So, when virus is executed, it just have to:
execute dB and decrypt poly
use SeedA and decrypted poly to create dA
decrypt virus with dA
...
There remains a lot of stuff to add, why not crypt SeedA with CryptC or
whatever you want.
This kind of virus can already make suffer an AVer for a half day, or perhaps
a whole day, but there is again some points to improve...
The purpose of that kind of stuff is that the AVer cannot see your pure
code passively (with IDA or some other disassembler) but must execute it
step by step to get a moment your decrypted code. If he execute it, we
have a chance... take it!
! Fooler stuffs :
1 Code mixing.
Function1:
...
ret
Function2:
...
jmp LblA
LblB: ...
ret
Var1 dd ?
LblA: ...
jmp LblB
is exactly the same as
Var1 dd ?
Function1:
...
ret
LblA: ...
jmp LblB
Function2:
...
jmp LblA
LblB: ...
ret
Even if Label trip from one function to another, the only difference is that
the code is no more divided logically, and is quite harder to understand if
we go further in complexity.
What I did:
In my code, after each JMP, each RET and each variable declaration, I write
on a new line ";cut-", and I made a short VB program, that open a text file,
divide it into blocs (blocs of lines enclosed by "cut-") and rewrite this
blocs in a random order in a new file... Even in sources, code can become
hard to understand.
2 Relocation changes.
When relocations are used, you often have something like [ebp+offset MyVar],
I just advice that, instead of
call SetEBP
SetEBP: pop ebp
sub ebp,offset SetEBP
... [ebp+offset MyVar]
we could use something like :
call SetEBP
RelocationBase = $
...
SetEBP: pop ebp
... [ebp+offset MyVar-RelocationBase]
First, the offset in memory operands can be a byte, so [ebp+00401000] take 3
bytes more than [ebp+05].
Secondly, it allow you to change your relocation base frequently, so that
[ebp+05] can mean something different depending on when you are in your code.
If even your code is mixed up, [ebp+5] can mean anything different from one
line to another.
3 Code variables.
An old good trick to avoid some long [ebp+...-...], it's always useful
to replace :
...
mov [ebp+offset myVariable],ebx
...
mov eax,[ebp+offset myVariable]
...
by :
...
mov [ebp+offset myVariable],ebx
...
mov eax,12345678h
myVariable = $-4
...
In fact, I should prefer to use :
...
mov [ebp+offset myVariable],ebx
...
db 0b8h ;mov eax,imm32
myVariable dd ?
...
because with that you can write stuff like "mov [ebp+imm32A],imm32B"
But it's just a question of preference.
note - you must have ring0 or have patched sections descs to be able to
write the code section.
There are also some coded variables more difficult to catch when debugging,
imagine you have:
Function1:
;Parametter: al = 0 => ...
; al = 1 => ...
mov [ebp+ParamAL],al
...
Loop: ...
cmp [ebp+ParamAL],0
jz somewhere
...
=> Loop
...
replace it by:
Function1:
or al,al
jz SetToJMP
mov [ebp+offset CndJmp-RelocBase],9090h ;nop ;nop
jmp ConditionSet
;cut-
SetToJMP:
mov [ebp+offset CndJmp-RelocBase], _
(offset somewhere - AfterCmdJmp) shl 8 + 0ebh
;0ebh = jmp rel8
ConditionSet:
...
Loop: ...
CndJmp db 2 dup (?)
AfterCmdJmp = $
...
=> Loop
...
This can be interesting here where it takes one more byte for the variable
and some more time in the loop, but even if it optimize your code, it make it
less understandable.
( Note that here the code is not that optimized, cuz the JZ/JMP pair can be )
( replaced by a CMOVZ and that a cmp/jz don't take that many bytes )
4 Fooled functions
For the example, I'll use the IFSMgr_Ring0_FileIO that always take a byte
for function in ah, that often become:
...
mov ebx,[ebp+offset FileHandle-RelocBase]
xor eax,eax
mov ah,FctNum
...
This can become something interesting like:
...
call SetEaxEbxForIFS
db FctNum
...
SetEaxEbxForIFS:
mov ebx,[ebp+offset FileHandle-RelocBase]
xor eax,eax
xchg esi,[esp]
lodsb
xchg esi,[esp]
xchg ah,al
ret
Like you see, creating a function for that was perhaps not necessary,
but will forbid the easy code analysis by some disassembler... the
"db FctNum" will become some strange op-code, and the code won't
be followed like that, or it can make the AVer work harder.
! Code keep on :
There are a lot of ways to run a program step by step. The worst, the most
complicated and the most hidden is to use the DebugRegister (dr0..dr3)
to set a breakpoint on the next op-code. You could get ring0 and use them
(even in ring3 under win9x) or verify them, but if the debuger is well-done
enough, you won't see anything.
The next way is quite the same, it's to set TF (Trap Flag) to 1, that's
a flag like CF, ZF, ... that, if set, raise an INT 1 b4 each op-code
executed. Like b4, if well-done enough, you won't see it. Note that this
way of doing avoid things like "step over", that mean execute a function
without getting inside, or execute "rep movsb" in only one step even
if ecx = 1000h
The last way, and the most used i think (but always less) is to change
the op-code that must raise a break-point with something like 0cch (int 3)
or 0f1h (int 1)... I think soft-ice use this with 0f1h (opcode often named
Ice-BreakPoint). If the debugger use this, a lot of chances open to us...
Imagine first that our fooled function (cf upper) is executed with a
"StepOver", what will happend? The byte folliwing the call (a parametter)
will be changed (into 0cch or 0f1h) so, 1st- code won't be broken, execution
will keep on, the AVer pushed the F8 key for step over, and the code is quite
well launched! What happend also is that, our argument (in our example
FctNum) will have a value of 0cch or 0f1h (or whatever), so, it will
have changed!
wahow! I'm executing my stuff, the AVer can't do anything against it
(don't forget that code is executed in less than 10-ý sec.) and I know I'm
debugged! Be creative!
Note: try to verify it quickly and to use some code never used (to destroy
something or likes) and that look like data (so AVer haven't put any
BreakPoint in it ), your code must be trapped from everywhere !
! Nuthin can stop you :
When you create a decrypt routine with your poly, you will then have a loop
that look like :
cld
mov edi,CryptedDataBegin
mov ecx,CryptedDataLenght
DecryptLoop:
mov al,[edi]
...
stosb
loop DecryptLoop
CryptedDataBegin = $
First, the debugger will execute the first loop, without getting further,
the first byte after the loop is decrypted, we can put a breakpoint on it.
So, let it be :
std
mov edi,CryptedDataBegin+CryptedDataLenght-1
mov ecx,CryptedDataLenght
DecryptLoop:
mov al,[edi]
...
stosb
loop DecryptLoop
CryptedDataBegin = $
Now, imagine that:
mov edi,CryptedDataBegin+CryptedDataLenght-1
mov ecx,CryptedDataLenght
mov al,Init_AL
DecryptLoop:
...
xchg al,[edi]
dec edi
loop DecryptLoop
CryptedDataBegin = $
With this system, you must have Init_AL, but that value is the value of
AL at the end of cryption, not that hard. The good point of this system is
that the first byte after the loop is useless (wow would you say, great! ;-)
but it mean that, at the end of decryption, AL will contain that byte (and
that byte will be what it must be, decrypted data, whatever it was),
So, if it has been changed by a break point, it won't change the code
execution, but will change AL value... and the expected AL value is the
one of before cryption (logic)...
Hereis another fool trap.
------------------
Ethic part
Like u c, i'm for a bit of destructive part, but i only suggest defensive
destruction, i mean the one that'll kill an AVer to avoid his interest fer
my work. Even for this i should advice carefulness and we should prefer
to use a gud code tht avoid virus analysis by any other way than destruction,
why not disinfect a puter and mark it as "AVer one" so that it cannot acces
my vir any more... The only limit is our imagination...
------------------
Notes:
1st - That tutorial was made by n0ph on the 19-12-99, for IKX, for XINE5.
2nd - If you find other tricks or objections please write n0ph@ikx4ever.org...
3rd - That's all folks!