Nytro Posted March 10, 2009 Report Posted March 10, 2009 # 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: PGelabert Enough, I say unto you first what her background for this tutorial to bringshould:-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 justThey 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 tutorialwrite) and born2die together with've found that the antivirus softwaremy backdoor was detected, and to me was what it was inexplicable, because it wasself-written software that would have no signature should be fit!It was the stinkin heuristic! 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 publishedandcopy 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 directorycopy!-------------------------what for me as much as said:-------------------------Suck my balls!-------------------------Well, joking aside. I had not long over, I knew that the antivirusGetWindowsDirectory 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 casethe antivirus program detects my requests to this API, but not if theynot exist in compiled state, but only after the run, very dynamic!Your asking how to do this? Well quite simply, we are not directly GetWindowsDirectorycall (so that our program is not directly imported, and thus the AV of nothingbescheid 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 tableincludes addresses for the respective functions imported (foreign dlls). Basedthis table one can understand what API functions the programused. You may also during the life functions, the room inappear in this table (used, for example, if a DLL at runtimebe). 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 willaccurately 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 havecan 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 andGetProcAddress function call and invite. Sun can be found in the executableState of the executable file does not contain information about eg GetWindowsDirectory onlyvia LoadLibrary and GetProcAddress.If these two functions do not say who would like to ask my Requirementsthrough, because as it is written: You should schonmal a DLLloaded!Well, the secret is revealed! We certainly is not clear yet how the wholenow 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 Inow 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 characterread the given. Which is now the ASCII value [=> see "(int) str [length]"].The ASCII value of "H" is 72ndThe following is this added value is 1. Therefore, the value 73rdNow, in "chr" back to the ASCII character is stored, from 73rdWhat was done here is simple: it was encrypted! A sign was in the alphabetfor a job after law postponed! It should therefore "I" arise, and it doestoo! So now with every other character to continue. Even with characters not in the alphabet arebecause it is yes to the ASCII table! Thus, a space with an exclamation mark, becausethe space is in the ASCII character table with the number 32, and the subsequent33 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 encryptas 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! XpsmePress 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 functiontest:)We will now make another try: OReplaced now that in the above "Hello World" with "MessageBoxA". It tells us:-------------------------NfttbhfCpyBPress 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?) Functionwith 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 theUnicode version.Depending on the setting of the compiler is a version of them selected. So you can eitheradjust 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!) Thenyou probably know, the two functions LoadLibrary and GetProcAddress. These areWe 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 msdnlook).Once we "dll" there, where we wanted it, we squeeze it in and say GetProcAddresshim 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 weMessageBox 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 downloadhad:)So, now follows a chapter for all those interested in reverse engineering (ie cracking) know, for alldo 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 recognizethe 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 arenot 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.Sleep00401348 | 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 butyou can not see! Since our program is' yes' to the start time (or before) does not knowthat 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 timedoes not know!We go back to the CPU window (click on the "C" in the menu) and make a quickClicking 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". Thuswe 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 stringdeciphered, 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 haltthe "Endspeicher", where the decrypted "MessageBoxA" is stored. The wholeProcedure 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 bytes00401322 A1 04304000 MOV EAX, DWORD PTR DS: [403004]00401327 8945 EC MOV DWORD PTR SS: [EBP-14], EAX; <- Next 4 bytes to copy0040132A 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 string00401335 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 hereafterfollows 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 EAX00401438 890424 | MOV DWORD PTR SS: [ESP], EAX; <- In ESP secure0040143B E8 F0050000 | CALL <JMP.&msvcrt.strlen>; <- investigating the length of the string00401440 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 EAX00401448 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 store00401451 8D45 F4 | LEA EAX, DWORD PTR SS: [EBP-C] <- EAX In the address at the current character00401454 FF08 | DEC DWORD PTR DS: [EAX] <- HERE! EAX decrease by one00401456 8B45 F4 | MOV EAX, DWORD PTR SS: [EBP-C] <- EAX in the decoded symbolFB 00401459 8845 | MOV BYTE PTR SS: [EBP-5], AL; <- EBP-5 In the latest sign store0040145C 8B45 08 | MOV EAX, DWORD PTR SS: [EBP +8] <- EAX has the address again to normal string0040145F 8B55 FC | MOV EDX, DWORD PTR SS: [EBP-4] <- EDX is 000401462 01C2 | ADD EDX, EAX; <- EAX add EDX On00401464 0FB645 FB | MOVZX EAX, BYTE PTR SS: [EBP-5] <- EAX is back in the decoded symbol00401468 8802 | MOV BYTE PTR DS: [EDX], AL; <- Decrypts characters in the string will be changed0040146A 8D45 FC | LEA EAX, DWORD PTR SS: [EBP-4]; <- Will increased (=> next character)0040146D FF00 | INC DWORD PTR DS: [EAX] <- and hingeschrieben0040146F 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! : PNext in the code. So that our F8 key not schimmelt tippseln we bit on it since, so we also come withback out from the CALL. And we see what is exciting! Traced as little down time, after theLine 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! : OWe recognize this HMODULE our of our code (as hex value in its natural form), andat 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 nowRight click "Goto -> Expression", the address, and schwupps, but it looks very much like aclean function, huh? OK, I think we have enough to getraced code, we have probably learned more (or not) as theTutorial 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 publishedSo 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 xDfrom this paper, so gehts doch;)So, as a sort of "annex" I have my whole source code here reinkopiert, have funorder, 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;)------------------------- Quote