其他基础知识:
单位换算:
- 1Byte(字节) = 8 bit(位)
- byte:字节(1Byte)
- word:字(2Byte)
- dword:双字(4Byte)
C数据类型典型大小
C声明 | C声明 | 字节数 | 字节数 |
---|---|---|---|
有符号 | 无符号 | 32位 | 64位 |
char | unsigned char | 1 | 1 |
short | unsigned short | 2 | 2 |
int | unsigned | 4 | 4 |
long | unsigned long | 4 | 8 |
int 8_t | uint_8 | 1 | 1 |
int 16_t | uint_16 | 2 | 2 |
int 32_t | uint_32 | 4 | 4 |
int 64_t | uint_64 | 8 | 8 |
char * | 4 | 8 | |
float | 4 | 4 | |
double | 8 | 8 |
windows基础
PE文件:
- EXE 和 DLL 都是 PE (Portable Executable)文件。每个PE含有一个导入和导出表。导入表指定导入函数以及这些函数所在的文件(模块)。导出表指定导出函数。
- Windows loader 从当前工作目录开始搜索DLLs,发布的某个应用可能具有一个不同于系统根(\windows\system32)目录中的DLL。版本方面的不兼容性被一些人称作DLL-hell。
- PE 文件提供 RVAs 来指定模块的相对基地址(指定 BASE ),VA = RVA + BASE。
线程:
- Windows 平台会为线程提供CPU时间片
- 可以用 CreateProcess() 创建新进程,用 CreateThreads() 创建新线程。线程会在它们所在进程的地址空间内执行,因此它们共享内存。
- 线程也会被一种称作 TLS(Thread Local Storage)的机制限制,该机制为线程提供了非共享内存。
- TEB 是 Thread Environment Block 的简写,同理 PEB 对应 Process Environment Block,两者分别储存与线程和进程相关的内容。
- 基本上,每个线程的 TEB 都含有一个 TLS 数组,它具有 64 个 DWORD 值,并且在运行过程中超出 TLS 数组的有效元素个数时,会为额外的 TLS 数组分配 1024 个 DWORD 值。首先,两个数组中的一个数组的每个元素会对应一个索引值,该索引值必须由 TlsAlloc() 分配或使用,可以用 TlsGetValue(index) 来读取DWORD 值并用 TlsSetValue(index, newValue) 将其写入。如,在当前线程的 TEB 中,TlsGetValue(7) 表示从 TLS 数组中索引值为 7 的地址上读取 DWORD 值。
TEB 结构:
TEB结构一般位于fs:[0]的位置,其声明如下:
typedef struct _NT_TEB
{
NT_TIB Tib; // 00h
PVOID EnvironmentPointer; // 1Ch
CLIENT_ID Cid; // 20h
PVOID ActiveRpcInfo; // 28h
PVOID ThreadLocalStoragePointer; // 2Ch
PPEB Peb; // 30h <--该位置给出了其对应的PEB的地址
ULONG LastErrorValue; // 34h
ULONG CountOfOwnedCriticalSections; // 38h
PVOID CsrClientThread; // 3Ch
PVOID Win32ThreadInfo; // 40h
ULONG Win32ClientInfo[0x1F]; // 44h
PVOID WOW32Reserved; // C0h
ULONG CurrentLocale; // C4h
ULONG FpSoftwareStatusRegister; // C8h
PVOID SystemReserved1[0x36]; // CCh
PVOID Spare1; // 1A4h
LONG ExceptionCode; // 1A8h
ULONG SpareBytes1[0x28]; // 1ACh
PVOID SystemReserved2[0xA]; // 1D4h
GDI_TEB_BATCH GdiTebBatch; // 1FCh
ULONG gdiRgn; // 6DCh
ULONG gdiPen; // 6E0h
ULONG gdiBrush; // 6E4h
CLIENT_ID RealClientId; // 6E8h
PVOID GdiCachedProcessHandle; // 6F0h
ULONG GdiClientPID; // 6F4h
ULONG GdiClientTID; // 6F8h
PVOID GdiThreadLocaleInfo; // 6FCh
PVOID UserReserved[5]; // 700h
PVOID glDispatchTable[0x118]; // 714h
ULONG glReserved1[0x1A]; // B74h
PVOID glReserved2; // BDCh
PVOID glSectionInfo; // BE0h
PVOID glSection; // BE4h
PVOID glTable; // BE8h
PVOID glCurrentRC; // BECh
PVOID glContext; // BF0h
NTSTATUS LastStatusValue; // BF4h
UNICODE_STRING StaticUnicodeString; // BF8h
WCHAR StaticUnicodeBuffer[0x105]; // C00h
PVOID DeallocationStack; // E0Ch
PVOID TlsSlots[0x40]; // E10h
LIST_ENTRY TlsLinks; // F10h
PVOID Vdm; // F18h
PVOID ReservedForNtRpc; // F1Ch
PVOID DbgSsReserved[0x2]; // F20h
ULONG HardErrorDisabled; // F28h
PVOID Instrumentation[0x10]; // F2Ch
PVOID WinSockData; // F6Ch
ULONG GdiBatchCount; // F70h
ULONG Spare2; // F74h
ULONG Spare3; // F78h
ULONG Spare4; // F7Ch
PVOID ReservedForOle; // F80h
ULONG WaitingOnLoaderLock; // F84h
PVOID StackCommit; // F88h
PVOID StackCommitMax; // F8Ch
PVOID StackReserve; // F90h
PVOID MessageQueue; // ???
}
PEB 结构:
结合 TEB 结构可知获取 PEB 首地址 fs:[30]
typedef struct _PEB
{
UCHAR InheritedAddressSpace; // 00h
UCHAR ReadImageFileExecOptions; // 01h
UCHAR BeingDebugged; // 02h <--用来判断程序是否在被调试的
UCHAR Spare; // 03h
PVOID Mutant; // 04h
PVOID ImageBaseAddress; // 08h
PPEB_LDR_DATA Ldr; // 0Ch
PRTL_USER_PROCESS_PARAMETERS ProcessParameters; // 10h
PVOID SubSystemData; // 14h
PVOID ProcessHeap; // 18h
PVOID FastPebLock; // 1Ch
PPEBLOCKROUTINE FastPebLockRoutine; // 20h
PPEBLOCKROUTINE FastPebUnlockRoutine; // 24h
ULONG EnvironmentUpdateCount; // 28h
PVOID* KernelCallbackTable; // 2Ch
PVOID EventLogSection; // 30h
PVOID EventLog; // 34h
PPEB_FREE_BLOCK FreeList; // 38h
ULONG TlsExpansionCounter; // 3Ch
PVOID TlsBitmap; // 40h
ULONG TlsBitmapBits[0x2]; // 44h
PVOID ReadOnlySharedMemoryBase; // 4Ch
PVOID ReadOnlySharedMemoryHeap; // 50h
PVOID* ReadOnlyStaticServerData; // 54h
PVOID AnsiCodePageData; // 58h
PVOID OemCodePageData; // 5Ch
PVOID UnicodeCaseTableData; // 60h
ULONG NumberOfProcessors; // 64h
ULONG NtGlobalFlag; // 68h 还有这里!_(:зゝ∠)_
UCHAR Spare2[0x4]; // 6Ch
LARGE_INTEGER CriticalSectionTimeout; // 70h
ULONG HeapSegmentReserve; // 78h
ULONG HeapSegmentCommit; // 7Ch
ULONG HeapDeCommitTotalFreeThreshold; // 80h
ULONG HeapDeCommitFreeBlockThreshold; // 84h
ULONG NumberOfHeaps; // 88h
ULONG MaximumNumberOfHeaps; // 8Ch
PVOID** ProcessHeaps; // 90h
PVOID GdiSharedHandleTable; // 94h
PVOID ProcessStarterHelper; // 98h
PVOID GdiDCAttributeList; // 9Ch
PVOID LoaderLock; // A0h
ULONG OSMajorVersion; // A4h
ULONG OSMinorVersion; // A8h
ULONG OSBuildNumber; // ACh
ULONG OSPlatformId; // B0h
ULONG ImageSubSystem; // B4h
ULONG ImageSubSystemMajorVersion; // B8h
ULONG ImageSubSystemMinorVersion; // C0h
ULONG GdiHandleBuffer[0x22]; // C4h
PVOID ProcessWindowStation; // ???
}
令牌
令牌通常是用于描述访问权限的一个 32 位整数。每个进程具有一个内部结构,该结构含有关于访问权限的信息,它与令牌相关联。
-
令牌分为两种类型:主令牌和模仿令牌。无论何时,某个进程被创建后都会被分配一个主令牌。进程的每个线程都可以拥有进程的令牌,或从另一进程中获取模仿令牌。如果 LogonUser() 函数被调用,则会返回一个不能被使用于 CreateProcessAsUser() (该函数功能是创建用户使用的一个子进程,一般的子进程都是由 system 启动的,这个是当前用户启动的。)的模仿令牌(提供凭据),除非你调用了 DupcateTokenEx() 来将其转换为主令牌。
-
可以使用 SetThreadToken(newToken) 将某个令牌附加到当前线程并且可以使用 RevertToSelf() 来将该令牌删除,从而让线程的令牌还原为主令牌。
-
我们来了解下在Windows平台上,将某个用户连接到服务器并发送用户名和密码的情况。首先以SYSTEM身份运行服务器,将会调用具有凭据的 LogonUser() ,如果成功则返回新令牌。接着会在服务器创建新线程的同时调用 SetThreadToken(new_token) ,new_token 参数是一个由 LogonUser() 返回的令牌值。这样,线程被执行时就具有与用户一样的权限。当线程完成了对客户端的服务时,或者会被销毁,或者将调用 revertToSelf() 而被添加到线程池的空闲线程队列中。
-
如果可以控制服务器,那么可通过调用 RevertToSelf() ,或在内存中查找其它的令牌并使用 SetThreadToken() 函数将它们附加到当前线程,从而恢复当前线程的权限,即 SYSTEM 权限。
-
值得注意的是,CreateProcess() 使用主令牌作为新进程的令牌。当具有比主令牌更高权限的模仿令牌的线程调用 CreateProcess() 时存在一个问题,那就是新进程的权限会低于创建该进程的线程。
-
解决方案是使用 DuplicateTokenEx() 从当前线程的模拟令牌中创建一个新的主令牌,接着通过调用具有新的主令牌的 CreateProcessAsUser() 创建新进程。