两个文件 make_shellcode.c 是编写同时也是生成shellcode的代码
load.c是测试加载shellcode的代码
make_shellcode.c
#include <stdio.h>
#include <stdint.h>
#include<windows.h>
void*(*GetLoadLibrary())(char*);
void* GetKernel32Base() ;
void* my_loadlib(char*libname);
int my_strcmp(char *s1, char *s2);
#define RVA_TO_VA(base, rva) ((uint8_t*)(base) + (rva))
void* GetFunctionAddress(void* module_base, char* func_name) ;
//shellcode入口 改写这个函数
int shellcode_main(){
char user32_str[7];
user32_str[0]='u';
user32_str[1]='s';
user32_str[2]='e';
user32_str[3]='r';
user32_str[4]='3';
user32_str[5]='2';
user32_str[6]=0;
char box_str[12];
box_str[0]='M';
box_str[1]='e';
box_str[2]='s';
box_str[3]='s';
box_str[4]='a';
box_str[5]='g';
box_str[6]='e';
box_str[7]='B';
box_str[8]='o';
box_str[9]='x';
box_str[10]='A';
box_str[11]=0;
void*user32=my_loadlib(user32_str);
int(*box)()=GetFunctionAddress(user32,box_str);
box(0,box_str,user32_str,1);
return 0;
}
void* GetKernel32Base() {
void* kernel32_base = 0;
__asm__ volatile (
"movl %%fs:0x30, %%eax\n" // EAX = PEB (通过TEB偏移0x30)
"movl 0x0C(%%eax), %%eax\n" // EAX = PEB->Ldr (PEB_LDR_DATA)
"movl 0x1C(%%eax), %%eax\n" // EAX = InInitializationOrderModuleList 第一个节点 (ntdll.dll)
"movl (%%eax), %%eax\n" // EAX = 第二个节点 (kernel32.dll)
"movl 0x08(%%eax), %0" // 节点偏移0x08处为基址
: "=r" (kernel32_base)
:
: "%eax"
);
return kernel32_base;
}
void* my_loadlib(char*libname){
void*(*loaddll)(char*)=GetLoadLibrary();
//printf("load %p\n",loaddll);
return loaddll(libname);
}
int my_strcmp(char *s1, char *s2) {
// 循环直到字符不同或任一字符串结束
while (*s1 && *s2 && (*s1 == *s2)) {
s1++;
s2++;
}
// 返回第一个不同字符的差值(处理符号问题)
return *(unsigned char*)s1 - *(unsigned char*)s2;
}
// RVA转实际地址(适用于已加载模块)
#define RVA_TO_VA(base, rva) ((uint8_t*)(base) + (rva))
void* GetFunctionAddress(void* module_base, char* func_name) {
// 1. 获取DOS头并验证
IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)module_base;
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) return NULL; // "MZ"标志检查:ml-citation{ref="1" data="citationList"}
// 2. 定位NT头
IMAGE_NT_HEADERS* nt_headers = (IMAGE_NT_HEADERS*)RVA_TO_VA(module_base, dos_header->e_lfanew);
if (nt_headers->Signature != IMAGE_NT_SIGNATURE) return NULL; // "PE"标志检查:ml-citation{ref="1" data="citationList"}
// 3. 获取导出表
IMAGE_DATA_DIRECTORY* export_dir = &nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
if (export_dir->VirtualAddress == 0 || export_dir->Size == 0) return NULL;
IMAGE_EXPORT_DIRECTORY* export_table = (IMAGE_EXPORT_DIRECTORY*)RVA_TO_VA(module_base, export_dir->VirtualAddress);
// 4. 遍历函数名数组
DWORD* name_rvas = (DWORD*)RVA_TO_VA(module_base, export_table->AddressOfNames);
WORD* ordinal_table = (WORD*)RVA_TO_VA(module_base, export_table->AddressOfNameOrdinals);
DWORD* func_addresses = (DWORD*)RVA_TO_VA(module_base, export_table->AddressOfFunctions);
for (DWORD i = 0; i < export_table->NumberOfNames; i++) {
const char* name = (const char*)RVA_TO_VA(module_base, name_rvas[i]);
if (my_strcmp(name, func_name) == 0) {
// 5. 通过序号获取函数地址
WORD ordinal = ordinal_table[i];
return (FARPROC)RVA_TO_VA(module_base, func_addresses[ordinal]);
}
}
return NULL;
}
void*(*GetLoadLibrary())(char*){
char name[13];
name[0]='L';
name[1]='o';
name[2]='a';
name[3]='d';
name[4]='L';
name[5]='i';
name[6]='b';
name[7]='r';
name[8]='a';
name[9]='r';
name[10]='y';
name[11]='A';
name[12]=0;
uintptr_t base = GetKernel32Base();
void*(*loaddll)(char*)=(void*(*)(char*))GetFunctionAddress(base,&name);
//printf("load %p\n",loaddll);
return loaddll;
}
void end(){
puts("end");
}
int main() {
FILE*f=fopen("code","wb");
DWORD size=(DWORD)end-(DWORD)shellcode_main;
fwrite(shellcode_main,size,1,f);
fclose(f);
}
load.c
#include<stdio.h>
#include<windows.h>
char code[1024*1024];
int main(){
DWORD d;
VirtualProtect(&code,sizeof(code),PAGE_EXECUTE_READWRITE,&d);
FILE*f=fopen("code","rb");
fread(&code,sizeof(code),1,f);
fclose(f);
int r=((int(*)())&code)();
}
编译运行 运行后shellcode存入 code文件 load.exe加载运行code文件
gcc make_shellcode.c -m32 -o make_shellcode
gcc load.c -m32 -o load
load