struct A0
{
};
struct A
{
int a;
int b;
};
struct AX
{
int a;
int b;
int max()
{
if (a > b)
return a;
else
return b;
}
};
sizeof(A0)==1
sizeof(A)== sizeof(AX)
AX.max
lea ecx,[ebp-8]
call max
push ecx
.....
pop ecx
访问 ecx中的数据 move [ebp-4],ecx
move eax,[ebp-4]
move ecx,[ebp-4]
取第一个值 move edx,[eax]
比较 cmp edx,[ecx+4]
访问父类私有成员
int *p = (int*)⊂
*(p+0)
* (p+1)
内存栈区从高到底 堆区从低到高
普通函数 E8 call 直接call
虚函数 FF call 间接call
虚函数表地址存在类的四字节起始位置 *(int*)&this
函数地址*((int*)(*(int*)&this)+i)
单继承 父类的函数地址在前面 子类会覆盖同名函数
多继承 多个虚函数表 1.无覆盖 子类虚函数放合并到第一个虚表里 第二个虚表放第二个父类的虚函数
2.有覆盖 覆盖的哪个在哪个表里
远程线程注入: createomtethread loadlibary 作为线程函数 GetThreadExitCode可以获取返回值
线程上下文
typedef struct _CONTEXT {
//
// The flags values within this flag control the contents of
// a CONTEXT record.
//
// If the context record is used as an input parameter, then
// for each portion of the context record controlled by a flag
// whose value is set, it is assumed that that portion of the
// context record contains valid context. If the context record
// is being used to modify a threads context, then only that
// portion of the threads context will be modified.
//
// If the context record is used as an IN OUT parameter to capture
// the context of a thread, then only those portions of the thread's
// context corresponding to set flags will be returned.
//
// The context record is never used as an OUT only parameter.
//
DWORD ContextFlags;
//
// This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
// set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
// included in CONTEXT_FULL.
//
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;
//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_FLOATING_POINT.
//
FLOATING_SAVE_AREA FloatSave;
//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_SEGMENTS.
//
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;
//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_INTEGER.
//
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;
//
// This section is specified/returned if the
// ContextFlags word contians the flag CONTEXT_CONTROL.
//
DWORD Ebp;
DWORD Eip;
DWORD SegCs; // MUST BE SANITIZED
DWORD EFlags; // MUST BE SANITIZED
DWORD Esp;
DWORD SegSs;
//
// This section is specified/returned if the ContextFlags word
// contains the flag CONTEXT_EXTENDED_REGISTERS.
// The format and contexts are processor specific
//
BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT;
Suspend(thread)
context. ContextFlags= CONTEXT_CONTROL.
Getthreadcontext(&context)
context.eip = 新地址
Setthreadcontext
1.typedef struct _RTL_CRITICAL_SECTION {
PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
//
// The following three fields control entering and exiting the critical
// section for the resource
//
等待线程的个数= LockCount- (RecursionCount-1)
LONG LockCount; ---当前使用临界区的线程 没有时是-1
LONG RecursionCount; --- 0或1 没占用就是0 有占用就是1
HANDLE OwningThread; // from the thread's ClientId->UniqueThread 线程ID
HANDLE LockSemaphore;
ULONG_PTR SpinCount; // force size on 64-bit systems when packed
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
关键段可以用于线程间的互斥,但不可以用于同步。
由于将线程切换到等待状态的开销较大,因此为了提高关键段的性能,Microsoft将旋转锁合并到关键段中,这样EnterCriticalSection()会先用一个旋转锁不断循环,尝试一段时间才会将线程切换到等待状态。下面是配合了旋转锁的关键段初始化函数
函数功能:初始化关键段并设置旋转次数
函数原型:
BOOLInitializeCriticalSectionAndSpinCount(
LPCRITICAL_SECTIONlpCriticalSection,
DWORDdwSpinCount);
函数说明:旋转次数一般设置为4000。
函数功能:修改关键段的旋转次数
函数原型:
DWORDSetCriticalSectionSpinCount(
LPCRITICAL_SECTIONlpCriticalSection,
DWORDdwSpinCount);
《Windows核心编程》第五版的第八章推荐在使用关键段的时候同时使用旋转锁,这样有助于提高性能。值得注意的是如果主机只有一个处理器,那么设置旋转锁是无效的。无法进入关键区域的线程总会被系统将其切换到等待状态。
最后总结下关键段:
1.关键段共初始化化、销毁、进入和离开关键区域四个函数。
2.关键段可以解决线程的互斥问题,但因为具有“线程所有权”,所以无法解决同步问题。
3.推荐关键段与旋转锁配合使用。
Event
1.事件是内核对象,事件分为手动置位事件和自动置位事件。事件Event内部它包含一个使用计数(所有内核对象都有),一个布尔值表示是手动置位事件还是自动置位事件,另一个布尔值用来表示事件有无触发。
2.事件可以由SetEvent()来触发,由ResetEvent()来设成未触发。还可以由PulseEvent()来发出一个事件脉冲。
3.事件可以解决线程间同步问题,因此也能解决互斥问题。
4 信号量Semaphone
信号量也可以解决线程之间的同步问题。
由于信号量可以计算资源当前剩余量并根据当前剩余量与零比较来决定信号量是处于触发状态或是未触发状态,因此信号量的应用范围相当广泛。
创建进程 创建个内核对象 维护空句柄表 内核和用户句柄不同 分配4GB虚拟空间 0-ffff 空指针用 10000-7FFEFFF 用户态用 64KB禁用区7FFF0000-7FFFFFFF 80000000-FFFFFFFF内核态
exe拉伸 dll拉伸 修复重定位表 修复全局变量 修复EXE/DLL 的IAT 创建线程 设置CONTEXT 执行线程。IMAGEBASE+OEP
句柄表 用户句柄 内核句柄 是否可继承
子进程继承父进程允许继承的内核对象
CreateProcess 挂起形式创建 进程没有加载任何dll 只是一个壳
获取外壳程序的入口点
Context context;
context.contextflag=context_full
GetThreadContext(hThread,&context);
入口点: context->eax
char* imagebase = (char*)context->ebx+8;
ReadProcessMemory(hProcess,buferr,size);
ResumeThread(hThread);
加密PE追加到父壳新增节
读取加密的pE
解密数据
挂起方式 CreateProcess 路径是壳本身
卸载程序文件镜像 zwUnmapViewOfSection
在指定位置申请指定大小的内存sizeofimage VirtualAllocEx 位置是imagebase
申请失败 判断pe的重定位表 如果有重定位表 在任意位置申请 否则返回失败
申请成功 将pe拉伸复制到指定位置
修改壳程序的Context 将Context的image改成pe的imagebase
将Context的Oep 改为 pe的OEP
设置Context 并恢复主线程
终止父外壳程序