PE基础5-权限提升-内存管理

权限管理

查询权限

BOOL QueryPrivileges()
{
// 1. 获得本进程的令牌
    HANDLE hToken = NULL;
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
        return false;
    // 2. 获取提升类型
    TOKEN_ELEVATION_TYPE ElevationType = TokenElevationTypeDefault;
    BOOL                 bIsAdmin = false;
    DWORD                dwSize = 0;
​
​
    if (GetTokenInformation(hToken, TokenElevationType, &ElevationType,
        sizeof(TOKEN_ELEVATION_TYPE), &dwSize)) {
        // 2.1 创建管理员组的对应SID
        BYTE adminSID[SECURITY_MAX_SID_SIZE];
        dwSize = sizeof(adminSID);
        CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, &adminSID, &dwSize);
​
​
        // 2.2 判断当前进程运行用户角色是否为管理员
        if (ElevationType == TokenElevationTypeLimited) {
​
            // a. 获取连接令牌的句柄
            HANDLE hUnfilteredToken = NULL;
            GetTokenInformation(hToken, TokenLinkedToken, (PVOID)&hUnfilteredToken,
                sizeof(HANDLE), &dwSize);
​
            // b. 检查这个原始的令牌是否包含管理员的SID
            if (!CheckTokenMembership(hUnfilteredToken, &adminSID, &bIsAdmin))
                return false;
            CloseHandle(hUnfilteredToken);
        }
        else {
            bIsAdmin = IsUserAnAdmin();
        }
        CloseHandle(hToken);
    }
    // 3. 判断具体的权限状况
    BOOL bFullToken = false;
    switch (ElevationType) {
    case TokenElevationTypeDefault: /* 默认的用户或UAC被禁用 */
        if (IsUserAnAdmin())  bFullToken = true; // 默认用户有管理员权限
        else                  bFullToken = false;// 默认用户不是管理员组
        break;
    case TokenElevationTypeFull:    /* 已经成功提高进程权限 */
        if (IsUserAnAdmin())  bFullToken = true; //当前以管理员权限运行
        else                  bFullToken = false;//当前未以管理员权限运行
        break;
    case TokenElevationTypeLimited: /* 进程在以有限的权限运行 */
        if (bIsAdmin)  bFullToken = false;//用户有管理员权限,但进程权限有限
        else           bFullToken = false;//用户不是管理员组,且进程权限有限
    }
​
    // 4. 根据权限的不同控制按钮的显示
    if (!bFullToken)
        Button_SetElevationRequiredState(::GetDlgItem(m_hWnd, IDC_BUTTON1), !bFullToken);
    else
        ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON1), SW_HIDE);
}

 

管理员启动

void OnBnClickedButton1()
{
// 1. 隐藏当前窗口
    //ShowWindow(hWnd, SW_HIDE);
    this->ShowWindow(SW_HIDE);
    // 2. 获取当前程序路径
    WCHAR szApplication[MAX_PATH] = { 0 };
    DWORD cchLength = _countof(szApplication);
    QueryFullProcessImageName(GetCurrentProcess(), 0,
        szApplication, &cchLength);
    // 3. 以管理员权限重新打开进程
    SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
    sei.lpVerb = L"runas";      // 请求提升权限
    sei.lpFile = szApplication; // 可执行文件路径
    sei.lpParameters = NULL;          // 不需要参数
    sei.nShow = SW_SHOWNORMAL; // 正常显示窗口
    if (ShellExecuteEx(&sei))
        exit(0);
    else
        ::ShowWindow(m_hWnd, SW_SHOWNORMAL);
}

 

遍历权限

//遍历权限
void ShowPrviliges()
{
//获取进程令牌句柄
    HANDLE hToken;
    OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
    if (!hToken)
    {
        printf("令牌获取失败\n");
        return;
    }
    //查询令牌中的权限
    DWORD dwSize;
    //第一次获取查询数据的大小
    GetTokenInformation(hToken,
        TokenPrivileges, NULL, NULL, &dwSize);
    //第二次根据上次获取的大小申请足够大的内存后,
    //将内存地址传进去获取想要的数据
    char* pBuf = new char[dwSize] {};
    GetTokenInformation(hToken,
        TokenPrivileges, pBuf, dwSize, &dwSize);
    //将内存中的内容用要查询数据结构体解析
    //这里事权限的结构体
    TOKEN_PRIVILEGES* pTp = (TOKEN_PRIVILEGES*)pBuf;
​
    //权限个数
    DWORD dwCount = pTp->PrivilegeCount;
    //指向权限数组首地址
    LUID_AND_ATTRIBUTES* pLaa = pTp->Privileges;
    //输出权限
    for (int i = 0; i < dwCount; i++, pLaa++)
    {
        char szName[100] = {};
        DWORD dwLen = sizeof(szName);
        //查询此权限对应的字符串
        LookupPrivilegeNameA(0, &pLaa->Luid, szName, &dwLen);
        //状态,0:关闭,1:默认值,2:开启,3:默认开启 
        printf("[%s] -- 状态[%d]\n", szName, pLaa->Attributes);
    }
    delete pBuf;}

 

提升权限

BOOL EnableDebugPrivilege(BOOL fEnable){  
    BOOL fOk = FALSE;    HANDLE hToken;
    // 以修改权限的方式,打开进程的令牌
    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES,
        &hToken)) {
        // 令牌权限结构体
        TOKEN_PRIVILEGES tp;
        tp.PrivilegeCount = 1;
        //获得LUID
        LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);
        tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
        //修改权限
        AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL); 
        fOk = (GetLastError() == ERROR_SUCCESS);
        CloseHandle(hToken);
    }
    return(fOk);
}

 

内存管理

Windows提供了以下3种方式管理内存数据

  • 堆:适合用来管理大量的小型对象,使用堆管理方式可以非常方便的帮我们管理所需要的内存空间,而无需去 关心一些细节问题,但是堆管理方式的效率较低,堆内存的控制不够灵活

  • 虚拟内存:适合用于管理大型的对象数组或大型的结构数组,使用虚拟内存管理方式有丰富的内存管理接口, 可以使我们更加精确的控制内存数据

  • 文件映射:适合用于管理大型的数据流,以及在同一个机器上的不同进程间共享数据

堆使用

int main()
{
    //创建堆可增长的
    HANDLE heap = HeapCreate(0, 0, 0);
    //系统信息
    SYSTEM_INFO sys;
    GetSystemInfo(&sys);
    //申请5个页面大小堆
    LPVOID pBuff = HeapAlloc(heap, HEAP_ZERO_MEMORY, sys.dwPageSize * 5);
    //读写堆内存
    memcpy(pBuff, "hello", 6);
    printf("%s\n", pBuff);
    //释放堆
    HeapFree(heap, HEAP_NO_SERIALIZE, pBuff);
    //销毁堆
    HeapDestroy(heap);
​
    //系统的默认堆
    HANDLE hProcessHeap = GetProcessHeap();
    LPVOID pbuff2 = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY,11 );
    //读写堆内存
    memcpy(pbuff2, "hello", 6);
    printf("%s\n", pbuff2);
    //不能使用DestroyHeap
    getchar();
}

 

虚拟内存

虚拟内存三种状态

空闲(free) : 进程不能访问这种页面,此页面还没有被分配 保留(reserve):这个页面被预定了。但是还未与物理内存映射,因此这里也是不能访问的 提交(commit): 内存已经被分配了,并且也与物理存储器映射了,进程已经可以访问这里

虚拟内存映射的三种方式:

private : 进程私有内存,不被其他进程所共享, 一般是堆,栈

mapped: 从别的内存映射而来

image : 从程序的PE映像映射而来,一般是映像的区段 虚拟内存的页面属性

READONLY :只读,只能从这个分页读取数据

READ_WRITE : 可读可写

EXECUTE : 可执行

EXECUTE_READ_WRITE : 可读可写可执行

WRITE_COPY : 写时拷贝 (用户不能使用)

使用虚拟内存

int main()
{
    //MEM_FREE    空闲,没有被使用
    //MEM_RESERVE 保留,没有与物理地址映射
    //MEM_COMMIT  提交,与物理地址进行映射
//1.申请虚拟内存空间
    LPVOID pBuff = VirtualAlloc(
        0,  //预定的地址,申请空间从这个地址开始
        1,  //申请空间的大小,默认对齐4kb
        MEM_RESERVE | MEM_COMMIT,  //预定并提交
        PAGE_READWRITE           //可写可读
    );
​
    //VirtualAllocEx 在其它进程中申请空间
//2.使用它
    memcpy(pBuff, "hello", 6);
    //3.释放内存
    VirtualFree(pBuff, 1, MEM_FREE);
    //VirtualFree 在其它进程中释放空间
​
​
    //修改内存分页属性
    char * pName = (char*)"hello";
    DWORD dwOldProtect;
    VirtualProtect(
        pName,          //修改的内存地址
        1,              //修改的大小,会分页对齐
        PAGE_READWRITE, //修改后的新属性
        &dwOldProtect); //修改前的原始属性
​
    pName[0] = 'x';
    //VirtualProtectEx 修改目标进程内存属性
}

 

文件映射

简单文操作

int main()
{
    //操纵一个文件,CreateFile,WriteFile,ReadFile
//1. 文件映射 速度快,无需申请空间
    HANDLE hFile = CreateFile(
        L"1.txt",
        GENERIC_WRITE| GENERIC_READ,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );
​
    //2.创建一个内存映射对象
    HANDLE hFileMap = CreateFileMapping(
        hFile, NULL, PAGE_READWRITE, 0, 0x10, L"test");
​
    //3.将物理地址映射到虚拟地址
    SIZE_T Size = 10;
    LPVOID pFileBuff = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, Size);
​
    //4.操作这段内存,写入数据
    memcpy(pFileBuff, "hello 15pb", 11);
​
    //5.刷新到文件
    FlushViewOfFile(pFileBuff, 10);
​
    //6.取消映射
    UnmapViewOfFile(pFileBuff);
​
    //7.关闭句柄
    CloseHandle(hFile);
    CloseHandle(hFileMap);
​
    
}

 

进程通信

进程A

int main()
{
    //1.创建文件映射
    HANDLE hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE,   //创建文件映射 -1
        NULL,                   //文件安全属性
        PAGE_READWRITE,         //页面属性
        0, 0x0100,
        L"15pb");
​
    //2.物理地址转换虚拟内存地址
    LPVOID lpBuff = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 10);
    //3.写入数据
    memcpy(lpBuff, "hello15pb", 10);
    //4.等待读取
    system("pause");
    //5.释放文件映射
    UnmapViewOfFile(lpBuff);
    CloseHandle(hFileMap);
    std::cout << "Hello World!\n"; 
}

 

        

进程B

int main() 
{ 
 //1.打开文件映射 
 HANDLE hFileMap =  
   OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, L"15pb"); 
 //2.将物理地址转换虚拟地址 
 LPVOID lPbuff = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS,0,0,10); 
 ///3.读写数据 
 printf("buff:%s\n", lPbuff); 
 //4. 取消映射关系 
 UnmapViewOfFile(lPbuff); 
 CloseHandle(hFileMap); 
 
} 

 

 

遍历内存

int main()
{
    //1.遍历进程 内存状态
    DWORD Addres = 0, Size = 0;
​
    //保存内存信息
    MEMORY_BASIC_INFORMATION Basicinfo = {};
​
    //遍历进程所有分页,输出内容
    while (VirtualQuery((LPCVOID)Addres, &Basicinfo, sizeof(MEMORY_BASIC_INFORMATION)))
    {
        Size = Basicinfo.RegionSize;
        printf("%08p  ", Basicinfo.BaseAddress);
​
        //当前状态
        switch (Basicinfo.State)
        {
        case MEM_FREE:      printf("空闲\n"); break;
        case MEM_RESERVE:   printf("保留\n"); break;
        case MEM_COMMIT:    printf("提交\n"); break;
        default:
            printf("未知\n");
            break;
        }
​
        //如果是提交状态的内存区域,那么遍历所有块中的信息
        if (Basicinfo.State == MEM_COMMIT)
        {
            //遍历所有基址是Address
            LPVOID BaseBlockAddress = (LPVOID)Addres;
            DWORD BlockAddress = Addres;
            DWORD dwBlockSize = 0;
​
            // 遍历大内存块中的小内存块
            while (VirtualQuery((LPVOID)BlockAddress, &Basicinfo, sizeof(Basicinfo)))
            {
                if (BaseBlockAddress != Basicinfo.AllocationBase)
                {
                    break;
                }
                printf("  %08X  ", BlockAddress);
                //查看内存状态,映射方式
                switch (Basicinfo.Type)
                {
                case MEM_PRIVATE:   printf("私有  "); break;
                case MEM_MAPPED:    printf("映射  "); break;
                case MEM_IMAGE:     printf("镜像  "); break;
                default:
                    printf("未知  ");
                    break;
                }
                if (Basicinfo.Protect == 0)
                    printf("---");
                else if (Basicinfo.Protect & PAGE_EXECUTE)
                    printf("E--");
                else if (Basicinfo.Protect & PAGE_EXECUTE_READ)
                    printf("ER-");
                else if (Basicinfo.Protect & PAGE_EXECUTE_READWRITE)
                    printf("ERW");
                else if (Basicinfo.Protect & PAGE_READONLY)
                    printf("-R-");
                else if (Basicinfo.Protect & PAGE_READWRITE)
                    printf("-RW");
                else if (Basicinfo.Protect & PAGE_WRITECOPY)
                    printf("WCOPY");
                else if (Basicinfo.Protect & PAGE_EXECUTE_WRITECOPY)
                    printf("EWCOPY");
                printf("\n");
                //计算所有相同块大小
                dwBlockSize += Basicinfo.RegionSize;
​
                // 累加内存块的位置
                BlockAddress += Basicinfo.RegionSize;
            }
            //内有可能大小位空
            Size = dwBlockSize ? dwBlockSize : Basicinfo.RegionSize;
    }
//下一个区域内存信息
Addres += Size;
    }
​
}

 

 

posted @ 2019-06-28 16:42  ltyandy  阅读(734)  评论(0编辑  收藏  举报