[Security] (5): shellcode code
18:08:45
In the previous section, we introduced the compilation of basic shellcode, using three system calls: exit (), setreuid (), and execve, in practice, You must select the appropriate system call based on your needs. You need to check the system call number.CallTable and parameter pushing are similar. It is not very difficult to compile assembly code to process the stack.
In this section, we will introduce the shellcode encoding. Why do we need to encode shellcode? There are several general causes:
- Avoid Bad characters, such as \ x00 and \ xa9;
- Avoids IDS or other network detector detection;
- Follow the string filter;
Next, we will briefly introduce a shellcode encoding method.
1. Simple XOR Encoding
A common bitwise operation in a computer is an XOR operation, that is, bitwise XOR ". It also took some effort to separate the operation from the "bitwise AND |" or "operation.The essence of an exclusive or operation is to determine whether the corresponding binary bit is the same. If the difference is --> exclusive --> True; if the difference is --> the same --> False. Therefore, we can say thatThe XOR operation is an operation that determines whether the corresponding binary bit is different.
XOR operations have good operation features, that is, a single number and a single number XOR will get itself twice:
0 XOR 0 = 00 XOR 1 = 11 XOR 1 = 01 XOR 0 = 1101 XOR 100 = 001001 XOR 100 = 101
We can use this feature to construct shellcode encoding and basic encryption. Of course, the key (0x100 in the above example) is hard-coded into shellcode.
Ii. JMP/call xor DecoderSince shellcode is encoded, it means decoding. Our model looks like the following:
[decoder][encoded shellcodes]
Generally, if the decoder needs to know its location, it can calculate the location of the encoded shellcode and start decoding. Determining the decoder location is usually calledThere are many GETPC methods. Today we will introduce one of them:JMP/CALL.
The idea of JMP/CALL is:
- Jump from JMP command to CALL command;
- The CALL command is located before the encoded shellcode;
- The CALL Command creates a new stack, so the current EIP pointer is pressed to the stack (that is, the starting address of the Code shellcode );
- During the CALL process, the address of the Pressure stack is popped up and saved to the Register;
- Use the stored registers for shellcode decoding;
- JMP is executed at shellcode;
It looks complicated. Let's take a look at the following assembly code to understand it. Pay attention to the execution sequence labels after each Assembly Statement, which can help you understand the entire process:
Global _ start_start: jmp short call_point; 1. JMP to CALLbegin: pop esi; 3. save the shellcode address in the stack to the esi register to facilitate subsequent Decoding of xor ecx and ecx; 4. clear ecxmov cl, 0x0; 5. shellcode is set to 0short_xor: xor byte [esi], 0x0; 6.0x0 is the code keyinc esi; 7. the ESI pointer increments and traverses all shellcode byte loop short_xor; 8. loop until the shellcode decoding is completed jmp short shellcodes; 9. skip the CALL and directly reach the shellcode segment call_point: call begin; 2. during the CALL begin process, the starting address of the current EIP, namely, the shellcode, is pushed into the shellcodes:; 10. the decoded shellcode is placed here. The decoded shellcode
The overall process is like this. As long as you pay close attention to the logic order and the pressure stack of the shellcode address, JMP/CALL is not hard to understand.
Refer: Gray Hat Hacking: The Ethical Hacker's Handbook, Third Edition