二进制基础

其他基础知识:

单位换算:

  • 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() 创建新进程。

你可能感兴趣的:(二进制,#,二进制基础)