博主某个二比朋友写的文章
1.基本没人教的花活,网上会有文章,但是不会解释原理。这玩意其实难度不高,就是要注意的东西多。
2.shellcode开发其实有很多办法,纯汇编,C和汇编又或者纯C++。(像我这种纯FW只能纯C++了)
3.搞明白下边的,写一个弹计算器的shellcode,私聊截图给我看,我手里还有花活,shellcode开发的进阶版。
无聊翻C2官方发现的,写出来我再教。
开发PIC shellcode注意事项
1.不能使用全局变量,或者用static修饰的变量·使用API时必须动态调用(GetProAddress)·确保调自定义shellcode入口点
2.·用API之前已经加载了与之对应的DLL
3.·所有字符串都必须要用字符串数组的方式替代
·属性——优化——O1/Ob2/Oi/Os/Oy/GL·
属性——代码生成———MT/GS-/GY·
属性——链接器——/INCREMENTAL:NO·
属性——链接器——调试——否
·属性——链接器——高级——入口点(自定义)
所有字符串都要用类似的格式去定义 unsigned char szUser32[] = { 'u','s','e','r','3','2','.','d','l','l',0 };防止破坏堆栈平衡
先看代码吧,代码是删减版只有模板
一个头文件comm.h,
#include <windows.h>
//这个其实没什么好说的这个头文件主要是在这边定义函数指针
typedef FARPROC(WINAPI* FN_GetProcAddress)(
_In_ HMODULE hModule,
_In_ LPCSTR lpProcName
);
typedef HMODULE(WINAPI* FN_LoadLibraryA)(
_In_ LPCSTR lpLibFileName
);
typedef int(WINAPI* FN_MessageBoxA)(
_In_opt_ HWND hWnd,
_In_opt_ LPCSTR lpText,
_In_opt_ LPCSTR lpCaption,
_In_ UINT uType);
typedef UINT(WINAPI* FN_WinExec)(
LPCSTR lpCmdLine,
UINT uCmdShow
);
typedef HANDLE(WINAPI * FN_CreateFileMappingW)(
_In_ HANDLE hFile,
_In_opt_ LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
_In_ DWORD flProtect,
_In_ DWORD dwMaximumSizeHigh,
_In_ DWORD dwMaximumSizeLow,
_In_opt_ LPCWSTR lpName
);
typedef struct tagApiInterface {
FN_GetProcAddress pfnGetProcAddress;
FN_LoadLibraryA pfnLoadLibrary;
FN_MessageBoxA pfnMessageBoxA;
FN_WinExec pfnWinExec;
FN_CreateFileMappingW pfnCreateFileMappingW;
}APIINTERFACE, * PAPIINTERFACE;
然后是function.h,一般存放一些自实现的函数,我把我的删掉了
#pragma once
#include "comm.h"
#include <windows.h>
#include <iostream>
#include <vector>
#include <cstdint>
using namespace std;
最后是最重要的,注意看注释。
大概的思路:通过PEB(不知道是啥玩意的自己去补基础)去获取Kernel32.dll的地址,从Kernel32.dll中获取导出函数GetProcAddress,再通过GetProcAddress函数获取LoadLibraryA函数。就可以实现从任意DLL中获取任意导出函数进行编程。
#include "comm.h"
#include <winternl.h>
#include "function.h"
// 获取Kernel32.dll模块的基地址
ULONGLONG GetModuleKernel64()
{
ULONGLONG dwKernel32Addr = 0;
// 获取TEB的地址
_TEB* pTeb = NtCurrentTeb();
// 获取PEB的地址
PULONGLONG pPeb = (PULONGLONG) * (PULONGLONG)((ULONGLONG)pTeb + 0x60);
// 获取PEB_LDR_DATA结构的地址
PULONGLONG pLdr = (PULONGLONG) * (PULONGLONG)((ULONGLONG)pPeb + 0x18);
// 模块初始化链表的头指针InInitializationOrderModuleList
PULONGLONG pInLoadOrderModuleList = (PULONGLONG)((ULONGLONG)pLdr + 0x10);
// 获取链表中第一个模块信息,exe模块
PULONGLONG pModuleExe = (PULONGLONG)*pInLoadOrderModuleList;
//printf("EXE Base = > %X \n", pModuleExe[6]);
// 获取链表中第二个模块信息,ntdll模块
PULONGLONG pModuleNtdll = (PULONGLONG)*pModuleExe;
//printf("Ntdll Base = > %X \n", pModuleNtdll[6]);
// 获取链表中第三个模块信息,Kernel32模块
PULONGLONG pModuleKernel32 = (PULONGLONG)*pModuleNtdll;
//printf("Kernel32 Base = > %X \n", pModuleKernel32[6]);
// 获取kernel32基址
dwKernel32Addr = pModuleKernel32[6];
return dwKernel32Addr;
}
// 通过解析PE格式的导出表,从给定的模块基地址中获取指定函数的地址
FARPROC getProcAddress(HMODULE hModuleBase)
{
// 获取DOS头
PIMAGE_DOS_HEADER lpDosHeader = (PIMAGE_DOS_HEADER)hModuleBase;
// 获取NT头
PIMAGE_NT_HEADERS64 lpNtHeader = (PIMAGE_NT_HEADERS64)((ULONG64)hModuleBase + lpDosHeader->e_lfanew);
// 检查导出目录的大小是否为0
if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) {
return NULL;
}
// 检查导出目录的虚拟地址是否为0
if (!lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress) {
return NULL;
}
// 获取导出目录的地址
PIMAGE_EXPORT_DIRECTORY lpExports = (PIMAGE_EXPORT_DIRECTORY)((ULONG64)hModuleBase + (ULONG64)lpNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
// 获取导出函数名称的地址
PDWORD lpdwFunName = (PDWORD)((ULONG64)hModuleBase + (ULONG64)lpExports->AddressOfNames);
// 获取导出函数名称序号的地址
PWORD lpword = (PWORD)((ULONG64)hModuleBase + (ULONG64)lpExports->AddressOfNameOrdinals);
// 获取导出函数地址的地址
PDWORD lpdwFunAddr = (PDWORD)((ULONG64)hModuleBase + (ULONG64)lpExports->AddressOfFunctions);
// 循环计数器
DWORD dwLoop = 0;
// 存储找到的函数地址
FARPROC pRet = NULL;
for (; dwLoop <= lpExports->NumberOfNames - 1; dwLoop++) {
// 获取当前函数名称的地址
char* pFunName = (char*)(lpdwFunName[dwLoop] + (ULONG64)hModuleBase);
// 检查函数名称是否为"GetProcAddress"
if (pFunName[0] == 'G' &&
pFunName[1] == 'e' &&
pFunName[2] == 't' &&
pFunName[3] == 'P' &&
pFunName[4] == 'r' &&
pFunName[5] == 'o' &&
pFunName[6] == 'c' &&
pFunName[7] == 'A' &&
pFunName[8] == 'd' &&
pFunName[9] == 'd' &&
pFunName[10] == 'r' &&
pFunName[11] == 'e' &&
pFunName[12] == 's' &&
pFunName[13] == 's')
{
// 找到函数名称,获取其地址
pRet = (FARPROC)(lpdwFunAddr[lpword[dwLoop]] + (ULONG64)hModuleBase);
break;
}
}
// 返回找到的函数地址
return pRet;
}
void EntryMain()
{
APIINTERFACE Api;
HMODULE hKernel32 = (HMODULE)GetModuleKernel64();
Api.pfnGetProcAddress = (FN_GetProcAddress)getProcAddress(hKernel32);
char szLoadLibraryA[] = { 'L','o','a','d','L','i','b','r','a','r','y','A',0 };
Api.pfnLoadLibrary = (FN_LoadLibraryA)Api.pfnGetProcAddress(hKernel32, szLoadLibraryA);

Comments NOTHING