Jump to content
Nytro

[C++] API Crypting

Recommended Posts

Posted

# Title: API crypting (Or: How to use the heuristic method of antivirus software austrickst)

# Date: 03.03.2008

# Author: Eddy14

# Website: www.eddys-blog.6x.to

# Email: eddy14@pen.tj

# Contents:

# # # 0x1 - Preface

# # # 0x2 - Introduction

# # # 0x3 - API commands

# # # 0x4 - The source code (and explanation)

# # # 0x5 - Deeper insight (Reverse Engineering)

# # # 0x6 - Conclusion / Links

_________________________

\ / \ / \ / \ / \ / 0x1 \ / \ / \ / \ / \ / \ /

#########################

Preface # #

#########################

Hello and welcome to my API crypting Tutorial:)

I wanted this paper before 2.5 months have finished, but somehow my Dev-C + +

strikes and I had otherwise no particular pleasure: P

Gelabert Enough, I say unto you first what her background for this tutorial to bring

should:

-Good knowledge of C (pointers, Typecasting, etc.)

Skills in Windows programming (The WinAPI!)

-You should ever have worked with DLLs (important, otherwise you confuse the DLL

-like code)

-You should have ever encrypted strings (Caesarean encryption is sufficient)

At the initiation gehts:)

_________________________

\ / \ / \ / \ / \ / 0x2 \ / \ / \ / \ / \ / \ /

#########################

Introduction # #

#########################

Well, first: Why I write this tutorial?

First, because too few tutorials I have written, and secondly, because I just

They were joined by a remote shell for Windows to write (a little backdoor; btw =>

to the remote shell, so generally pipes under Windows, I will also be a tutorial

write) and born2die together with've found that the antivirus software

my backdoor was detected, and to me was what it was inexplicable, because it was

self-written software that would have no signature should be fit!

It was the stinkin heuristic! :-O

In my program was implemented something that was around this building:

-------------------------

GetWindowsDirectory (& buffer, sizeof (buffer));

CopyFile (argv [0], buffer, FALSE);

-------------------------

(intermediate or strcat to append the file name)

What the Windows as much as said:

-------------------------

Find your Windows directory published

and

copy me then!

-------------------------

Antivir for what it looked like:

-------------------------

Buuuh, I'm Bööööse and a virus!

I am now totally leet itself into the Windows directory

copy!

-------------------------

what for me as much as said:

-------------------------

Suck my balls!

-------------------------

Well, joking aside. I had not long over, I knew that the antivirus

GetWindowsDirectory the program and the subsequent CopyFile recognized as malware

(do not know any other software that makes sense to use something, or maybe?). In any case

the antivirus program detects my requests to this API, but not if they

not exist in compiled state, but only after the run, very dynamic!

Your asking how to do this? Well quite simply, we are not directly GetWindowsDirectory

call (so that our program is not directly imported, and thus the AV of nothing

bescheid white) but only when you run!

It is very simple. You should format the PE (Portable Exectuable) a look.

There you will at some point on the IAT (Import Address Table) encounter. This table

includes addresses for the respective functions imported (foreign dlls). Based

this table one can understand what API functions the program

used. You may also during the life functions, the room in

appear in this table (used, for example, if a DLL at runtime

be). That said I do with "dynamic".

(more on the IAT can be found here: http://sandsprite.com/CodeStuff/Understanding_imports.html)

Your question is still how it works?

Then read the first chapter "API commands," and in "source code" Part I will

accurately explain everything:)

_________________________

\ / \ / \ / \ / \ / 0x3 \ / \ / \ / \ / \ / \ /

#########################

API commands # #

#########################

First, the three "commands" we try to use:

-GetWindowsDirectory (GetWindowsDirectoryA)

CopyFile -

-MessageBox (MessageBoxA)

And the two major commands without the API crypting probably would not be possible:

LoadLibrary -

GetProcAddress -

_________________________

\ / \ / \ / \ / \ / 0x4 \ / \ / \ / \ / \ / \ /

#########################

# # The source code

#########################

Since you now know what API calls we need, you will hopefully have

can think what comes now. Or still not?

Well, I vent the whole secret:

We will present our views as strings encrypt, and then via LoadLibrary and

GetProcAddress function call and invite. Sun can be found in the executable

State of the executable file does not contain information about eg GetWindowsDirectory only

via LoadLibrary and GetProcAddress.

If these two functions do not say who would like to ask my Requirements

through, because as it is written: You should schonmal a DLL

loaded!

Well, the secret is revealed! We certainly is not clear yet how the whole

now operate. I will now perform code and of course as always, explain:)

BTW, I use raw here GCC under Windows, Dev-C + + rum sucked, that's why.

-------------------------

# include <stdio.h>

# include <windows.h>

int main (int argc, char * argv [])

(

char hello [] = "Hello World";

crypt (& hello);

printf ( "% s \ n", hello);

system ( "PAUSE");

return 0;

)

-------------------------

Here you can see in advance what our test program to make. There is a so-called "crypt"

Function of our test-string and then the printed output (+ waits for additional input).

That is something everybody should have understood, because in principle, go here just about the "crypt" function which I

now this show:

-------------------------

int crypt (char * str)

(

int length;

char chr;

int ord;

for (length = 0; length <strlen (str); length + +)

(

ord = (int) str [length];

ord = ord + 1;

chr = (char) ord;

str [length] = chr;

)

return 0;

)

-------------------------

Sooo bad it looks or garnicht?

Our loop goes through all the characters. With each pass, the current character

read the given. Which is now the ASCII value [=> see "(int) str [length]"].

The ASCII value of "H" is 72nd

The following is this added value is 1. Therefore, the value 73rd

Now, in "chr" back to the ASCII character is stored, from 73rd

What was done here is simple: it was encrypted! A sign was in the alphabet

for a job after law postponed! It should therefore "I" arise, and it does

too! :)

So now with every other character to continue. Even with characters not in the alphabet are

because it is yes to the ASCII table! Thus, a space with an exclamation mark, because

the space is in the ASCII character table with the number 32, and the subsequent

33 is an exclamation point:)

Now get even briefly thought about the Decrypt method. Well how is this most like?

Well exactly, except that instead of subtracting, 1 adds.

-------------------------

int decrypt (char * str)

(

int length;

char chr;

int ord;

for (length = 0; length <strlen (str); length + +)

(

ord = (int) str [length];

ord = ord - 1;

chr = (char) ord;

str [length] = chr;

)

return 0;

)

-------------------------

Ready is our encryption method. You can string me from encrypt

as you want, you can hauptsache decrypt it again.

We now test our program:

-------------------------

# include <stdio.h>

# include <windows.h>

int main (int argc, char * argv [])

(

char hello [] = "Hello World";

crypt (& hello);

printf ( "% s \ n", hello);

system ( "PAUSE");

return 0;

)

int crypt (char * str)

(

int length;

char chr;

int ord;

for (length = 0; length <strlen (str); length + +)

(

ord = (int) str [length];

ord = ord + 1;

chr = (char) ord;

str [length] = chr;

)

return 0;

)

int decrypt (char * str)

(

int length;

char chr;

int ord;

for (length = 0; length <strlen (str); length + +)

(

ord = (int) str [length];

ord = ord - 1;

chr = (char) ord;

str [length] = chr;

)

return 0;

)

-------------------------

For the readers of the GCC USEN (which will probably already know how you compiled: P):

-------------------------

cryptme.c gcc-o cryptme.exe

-------------------------

Starts it and what you see? There are ...

-------------------------

Ifmmp! Xpsme

Press any key. . .

-------------------------

... from. Our "Hello World" means encrypted (using our algorithm):

-------------------------

Ifmmp! Xpsme

-------------------------

OK good. Now everything runs ever. If you absolutely want to, you can also decrypt function

test:)

We will now make another try: O

Replaced now that in the above "Hello World" with "MessageBoxA". It tells us:

-------------------------

NfttbhfCpyB

Press any key. . .

-------------------------

As you probably suspected, we will for our attempts to encrypt MessageBox.

Perhaps you ask why we MessageBoxA MessageBox and not encrypt?

To be exact, there is no MessageBox. Windows is generally (any?) Function

with strings works for 2 versions. One that ends with A and one that ends with W.

Those with a question, the ASCII versions, and with W (for Wide Char) for the

Unicode version.

Depending on the setting of the compiler is a version of them selected. So you can either

adjust the settings, or use the versions directly (instead of "MessageBox" So

"MessageBoxA" in the code example).

Ok, jump back on again we Topic (little English must be;))

If you ever have worked with DLLs (if not, then I urge you once again!) Then

you probably know, the two functions LoadLibrary and GetProcAddress. These are

We now use our encrypted features!

Let go! (bit directly translated: P)

-------------------------

int main (int argc, char * argv [])

(

func_crypted char [] = "NfttbhfCpyB";

HMODULE dll;

FARPROC MyMessageBox;

decrypt (& func_crypted);

dll = LoadLibrary ( "user32.dll");

MyMessageBox = GetProcAddress (dll, func_crypted);

MyMessageBox (0, "In working dude;)", "yeaaah", MB_OK);

system ( "PAUSE");

return 0;

)

-------------------------

We declare "dll" and "MyMessageBox" for later use with LoadLibrary and GetProcAddress.

Then we invite user32.dll (because there is our declared MessageBox, which you can find everything in the msdn

look).

Once we "dll" there, where we wanted it, we squeeze it in and say GetProcAddress

him at the same time that the function to be loaded into "func_crypted" exists. You know from

"NfttbhfCpyB" is well known "MessageBoxA" has become. So we say it is not more than:

-------------------------

Loading from the user32.dll function MessageBoxA

-------------------------

Then we finally have everything we want in MyMessageBox! We can now just call it as we

MessageBox with it (or MessageBoxA) would have done.

Alright dudes? =)

In the case of GetWindowsDirectory was not much different, except that I kernel32.dll instead user32.dll download

had:)

So, now follows a chapter for all those interested in reverse engineering (ie cracking) know, for all

do not go in this area, please skip, it was probably just confused!

_________________________

\ / \ / \ / \ / \ / 0x5 \ / \ / \ / \ / \ / \ /

#########################

Deeper insight # #

#########################

So their leet cracker: P throws your Lieblingsdisassembler times (in my case OllyDBG).

I will all the steps in this case with OllyDBG explain.

Compiled try this source:

-------------------------

# include <stdio.h>

# include <windows.h>

int main ()

(

Sleep (1000);

MessageBox (0, "test", "test", MB_OK);

return 0;

)

-------------------------

It is useless, I know! But it is only for better understanding. As you can easily recognize

the program waits for one second, then a MessageBox to display.

This program we invite now Olly.

CPU goes into the window (ie, the status of their results as soon as a program in Olly loads,

expresses the safe side "C" at the top of the toolbar) and now makes a right click.

Now it selects "Search for -> All inter-modular calls. Looks exactly as you order, there are

not really much to read. At best it looks you in the area below the red line around.

Here what you will discover:

-------------------------

00401321 | CALL <JMP.&KERNEL32.Sleep> | kernel32.Sleep

00401348 | CALL <JMP.&USER32.MessageBoxA> | USER32.MessageBoxA

-------------------------

(The addresses may vary)

You can see that 2 functions implemented (or otherwise: gecalled) are.

Once our sleep, and once our MessageBox.

That would be an antivirus program can recognize. For our encryption but

you can not see! Since our program is' yes' to the start time (or before) does not know

that he is equal to a function name and the corresponding decrypt function is!

So, now it compiles times MessageBoxA our example and invites it in Olly.

Your back is "Search for -> All inter-modular calls and lands back in the same window.

Take a look back at the red line around, and it recognizes your API calls!

LoadLibraryA, GetProcAddress, and system and a few others:)

But hm, where is our MessageBoxA? Den gibts nicht! Since our program is at this time

does not know!

We go back to the CPU window (click on the "C" in the menu) and make a quick

Clicking in the box below left, then right click and select "Search for -> binary string".

First, we select "Entire block" and then jump in the ASCII range and type ...

-------------------------

NfttbhfCpyB

-------------------------

... one. This is our Encrypted "MessageBoxA" if you should forget it.

Olly And there was! You see, it was not detected a function call.

Let's go a little further, it also means "insight". Thus

we have a breakpoint on the string. Mark it, make a right click, go to "Point Break"

and you see a small menu. We want to be a hardware breakpoint, but on "Access"

or "Write"?

If we make one in Access, then we would probably break if the string

deciphered, and it is called (ie for GetProcAddress is used).

Or we take "Write" and then immediately break when we start the string to decrypt.

We take the latter;) And be a DWORD (for safety's sake).

Once F9 and off you go! We break to:

-------------------------

0040131A A1 00304000 MOV EAX, DWORD PTR DS: [403000]

0040131F 8945 E8 MOV DWORD PTR SS: [EBP-18], EAX; <- HERE

-------------------------

Hm, but what's in EAX? I can tell you! "7474664E" equivalent "ttfN" ie "Nftt"

which means that the first 4 bytes from Crypteten string copied:)

Now they are in EBP-18 is stored. That will be the "cache" or halt

the "Endspeicher", where the decrypted "MessageBoxA" is stored. The whole

Procedure with the copy line:

-------------------------

0040131A A1 00304000 MOV EAX, DWORD PTR DS: [403000]

0040131F 8945 E8 MOV DWORD PTR SS: [EBP-18], EAX; <- First copy 4 bytes

00401322 A1 04304000 MOV EAX, DWORD PTR DS: [403004]

00401327 8945 EC MOV DWORD PTR SS: [EBP-14], EAX; <- Next 4 bytes to copy

0040132A A1 08304000 MOV EAX, DWORD PTR DS: [403008]

0040132F 8945 F0 MOV DWORD PTR SS: [EBP-10], EAX; <- Next 4 bytes ...

00401332 8D45 E8 LEA EAX, DWORD PTR SS: [EBP-18] <- EAX is now in the address to string

00401335 890424 MOV DWORD PTR SS: [ESP], EAX; <- This is stored in ESP

-------------------------

I wonder why the degree of the compiler has done so cumbersome, but maybe. Shortly hereafter

follows a call!

-------------------------

00401338 E8 EB000000 CALL 00401428; <- Decrypt

-------------------------

As my comment has already promised, here is decrypted! So once we trace pure,

so that our F7 key also something to do:)

-------------------------

00401435 8B45 08 / -> MOV EAX, DWORD PTR SS: [EBP +8]; <- In the string load EAX

00401438 890424 | MOV DWORD PTR SS: [ESP], EAX; <- In ESP secure

0040143B E8 F0050000 | CALL <JMP.&msvcrt.strlen>; <- investigating the length of the string

00401440 3945 FC | CMP DWORD PTR SS: [EBP-4], EAX; <- All characters by?

00401443 73 2C | JNB SHORT 00401471; <- Then times jumping out of the loop!

00401445 8B45 08 | MOV EAX, DWORD PTR SS: [EBP +8]; <- The addresses to the string in EAX

00401448 0345 FC | ADD EAX, DWORD PTR SS: [EBP-4] <- The current character ...

0040144B 0FBE00 | MOVSX EAX, BYTE PTR DS: [EAX] <- EAX copy in ...

0040144E 8945 F4 | MOV DWORD PTR SS: [EBP-C], EAX; <- In EBP-C store

00401451 8D45 F4 | LEA EAX, DWORD PTR SS: [EBP-C] <- EAX In the address at the current character

00401454 FF08 | DEC DWORD PTR DS: [EAX] <- HERE! EAX decrease by one

00401456 8B45 F4 | MOV EAX, DWORD PTR SS: [EBP-C] <- EAX in the decoded symbol

FB 00401459 8845 | MOV BYTE PTR SS: [EBP-5], AL; <- EBP-5 In the latest sign store

0040145C 8B45 08 | MOV EAX, DWORD PTR SS: [EBP +8] <- EAX has the address again to normal string

0040145F 8B55 FC | MOV EDX, DWORD PTR SS: [EBP-4] <- EDX is 0

00401462 01C2 | ADD EDX, EAX; <- EAX add EDX On

00401464 0FB645 FB | MOVZX EAX, BYTE PTR SS: [EBP-5] <- EAX is back in the decoded symbol

00401468 8802 | MOV BYTE PTR DS: [EDX], AL; <- Decrypts characters in the string will be changed

0040146A 8D45 FC | LEA EAX, DWORD PTR SS: [EBP-4]; <- Will increased (=> next character)

0040146D FF00 | INC DWORD PTR DS: [EAX] <- and hingeschrieben

0040146F EB ^ C4 \ - JMP SHORT 00401435; <- back to the beginning of loop

-------------------------

Oh man! So much to read and understand! The comments should enhance the adventure, however;)

In brief: All characters by one humiliate! Even shorter: Decrypt!

But it is always nice to see what the compiler of our beautiful C code does not it? =)

So, now we are setting a breakpoint after the JMP, allow the program to break,

and now have our unencrypted "MessageBoxA" in memory lying ===)

You do not believe me? Power for a short GOTO 0022FF60, owned, and the sight of you! : P

Next in the code. So that our F8 key not schimmelt tippseln we bit on it since, so we also come with

back out from the CALL. And we see what is exciting! Traced as little down time, after the

Line with "% s", we see a "user32.dll", which looks very nice!

And then there is a CALL to LoadLibraryA, and a little bit below make a GetProcAddress.

Uhh have you also this tingling in the abdomen when everything is running perfectly? ;)

We turn times a breakpoint at the call to GetProcAddress because I have what you want to show!

If Olly breaked look her in the stack.

-------------------------

0022FF20 7E360000 | 7E360000 = hModule (user32)

0022FF24 0022FF60 \ ProcNameOrOrdinal = "MessageBoxA"

-------------------------

Just so much information at once! : O

We recognize this HMODULE our of our code (as hex value in its natural form), and

at the same time we recognize that we in the user32 and after "MessageBoxA".

We step through this short time and then see CALL EAX into a miracle, our MessageBox was loaded!

For me it is "7E3A058A," and when I look in the user32.dll would => It would agree;)

You can convince yourself, right click the CPU window, "View -> Modules' user32 '' and now

Right click "Goto -> Expression", the address, and schwupps, but it looks very much like a

clean function, huh? :)

OK, I think we have enough to getraced code, we have probably learned more (or not) as the

Tutorial should provide. I hope part of you has fallen, if you've read through it ^ ^

_________________________

\ / \ / \ / \ / \ / 0x6 \ / \ / \ / \ / \ / \ /

#########################

# Degree / Links #

#########################

Pffft, then again from me:)

The paper is unfortunately not as long as I have, I had hoped: /

But I hope at least one which has learned from this tutorial:)

This paper is released under the GNU Free Documentation License has been published

So it is allowed to modify and distribute as you like, as long as my name on it still stands.

Oh you know what, you can even get my name clear because the main people learn xD

from this paper, so gehts doch;)

So, as a sort of "annex" I have my whole source code here reinkopiert, have fun

order, and to read again:)

cryptme.c

-------------------------

# include <stdio.h>

# include <windows.h>

int main (int argc, char * argv [])

(

char hello [] = "Hello World";

crypt (& hello);

printf ( "% s \ n", hello);

system ( "PAUSE");

return 0;

)

int crypt (char * str)

(

int length;

char chr;

int ord;

for (length = 0; length <strlen (str); length + +)

(

ord = (int) str [length];

ord = ord + 1;

chr = (char) ord;

str [length] = chr;

)

return 0;

)

int decrypt (char * str)

(

int length;

char chr;

int ord;

for (length = 0; length <strlen (str); length + +)

(

ord = (int) str [length];

ord = ord - 1;

chr = (char) ord;

str [length] = chr;

)

return 0;

)

-------------------------

mymessagebox.c

-------------------------

# include <stdio.h>

# include <windows.h>

int main (int argc, char * argv [])

(

func_crypted char [] = "NfttbhfCpyB";

HMODULE dll;

FARPROC MyMessageBox;

decrypt (& func_crypted);

dll = LoadLibrary ( "user32.dll");

MyMessageBox = GetProcAddress (dll, func_crypted);

MyMessageBox (0, "In working dude;)", "yeaaah", MB_OK);

system ( "PAUSE");

return 0;

)

int crypt (char * str)

(

int length;

char chr;

int ord;

for (length = 0; length <strlen (str); length + +)

(

ord = (int) str [length];

ord = ord + 1;

chr = (char) ord;

str [length] = chr;

)

return 0;

)

int decrypt (char * str)

(

int length;

char chr;

int ord;

for (length = 0; length <strlen (str); length + +)

(

ord = (int) str [length];

ord = ord - 1;

chr = (char) ord;

str [length] = chr;

)

return 0;

)

-------------------------

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...