zoukankan      html  css  js  c++  java
  • 进程启动时主线程创建过程分析

    VS2013编译以下代码:

    #include "stdafx.h"

    int _tmain(int argc, _TCHAR* argv[])
    {
        int test = 1;
        test = 2;

        return 0;
    }

    使用CFF Explorer或者PEID打开编译后生成的exe文件,查看imageBase和OEP,如下所示:

    OEP:  0x00011073

    image

    ImageBase:0x00400000

    image

    所以该程序的启动点在:0x00411073

    该程序的区段信息如下所示:

    image

    将其载入OD,其载入地址并非00400000,所以载入OD后,alt+e,先看看主模块的载入地址:

    image

    一般进程运行时都是先载入该exe文件,所以exe总能以其imagebase载入,但这里不知这个是为什么,这里可以不用管这个,直接以其载入地址0x00390000进行后面的分析,但是鄙人有强迫症,总想搞清楚这是为什么,所以先来看下为什么不能以imagebase载入。

    联想到安全机制ASLR,难道是这个原因?多次载入,果然发现多次载入时主模块的载入地址每次都不同。。。

    隐约记得VC6.0是不支持ASLR的,所以下面用VC6.0重新编译以下代码
    #include "stdafx.h"

    int main(int argc, char* argv[])
    {
        printf("Hello World! ");
        return 0;
    }

    果然,每次载入地址都是00400000,那么VS2013的ASLR是不是也可以关闭呢?记得好像哪里有说过可以关闭,找一找。。。

    强大的网友:

    ---------------------------------------------------------------------------------------------------

    通过加载程序时候不再使用固定的基址加载,从而干扰shellcode定位的一种保护机制

    windows Vista出现后,ASLR 才真正开始发挥作用

    VS2005 添加 /dynmicbase 就可以支持 ASLR

    VS2008 linker->Randomized Base Address 设置

    包含 映像随机化,堆栈随机化,PEB+TEB随机化

    ---------------------------------------------------------------------------------------------------

    image

    果然,将其关闭,再次测试

    备注:关闭后,少了一个区段reloc,这个此处不分析为什么

    image

    搞定,此处只是为了便于多次分析,所以关闭ASLR,正常情况,为了安全还是要将ASLR打开的



    下面从基地址(0x00400000)开始分析,如下所示:

    我们知道PE文件在内库中是以1000h(一页)对其,所以先看该页:

    image

    。。。。。。

    image

    。。。。。。

    end

    这部分数据全是PE文件的结构数据,各种头部,区段数据等,和本主题没关系,继续向下第二页:

    0x00401000,PEID和OD都可以知道这部分数据是.textbbs,

    image

    0x00401000---0x00402000这一页内存,结果全是0,《程序员的自我修养》中说“.bbs”段存放的是为初始化的全局变量和局部静态变量,这里没有用到未初始化的全局变量和局部静态变量,所以全是0.

    下一个区段:.text(0x00411000

    段在OEP,看OEP的代码

    image

    这个是OD自动断下来的第一条指令,查看堆栈:

    image

    去0x75DF3388看看

    image

    在此处3388处下F2断点,Ctrl+F2重启进程,在此处断下来,发现堆栈中没有任何信息,继续向前走,我们在0x75DF3378和0x75DF337A处下断点,重启进程

    image

    先看从3385~338B

    push 主线程参数;

    call 主线程函数;(通过OEP做了一次跳板)

    push 主线程返回值;

    call ntdll.RtlExitUserThread

    其源代码应是:RtlExitUserThread((OEP[jmp到主线程入口main])(参数));

    通过Windbg调试发现jnz kernel32.75DF6202处其实是:kernel32!RegSetValueExW+0x655 (75df6202),其功能自行百度,此处具体做了什么先不分析了。。。好复杂。。。

    此时的堆栈信息如下:

    image

    此时第一条堆栈信息是当前函数的名字:即0x75DF3378是kernel32.BaseThreadInitThunk函数

    在这四条堆栈信息中函数过程处下断点,Crtl+F2

    然而结果如下:

    image

    前面的位置断不下来,所以从最后一条堆栈信息查看,结果如下:

    image

    原来此处是ntdll的入口,应该是类似于dllmain的,继续看第二条堆栈信息:

    image

    表示不认识,第一条:

    image

    依旧不认识。

    但是调试发现0x75DF3378会被调用两次,第一次其实并未走到OEP,第二次才会call oep,所以此处再调试一次,等第二次调用0x75DF3378时,堆栈信息如下:

    image

    我们去0x77E49F40处看看:

    image

    初始化了异常处理链SEH,最终调用BaseThreadInitThunk,但是谁调用了0x77E49F2A?堆栈是空的?jmp?

    上IDA?

    结果发现ntdll不是以imagebase载入的,所以需要换算:77E49F2A-77E10000=39F2A

    image

    ntdll的imagebase:

    image

    所以7DE70000+39F2A=7DEA9F2A就是IDA中77E49F2A的位置。

    结果如下:

    image

    所以,创建主线程的入口应该是ntdll!RtlUserThreadStart,至于其具体做了什么,可以在IDA中详细查看,

    这里再不分析了。

    感觉好像丢了什么,算了,就这样吧,睡了。

    另附:Windows核心编程(第5版)153页的以下代码:

    Void RtlUserThreadStart(PTHREAD_START_ROUTINE pfnStartAddr, PVOID pvParam)

    {

    __try{

                   ExitThread((pfnStartAddr)(pvParam));

             }

    __except(UnhandledExceptionFilter(GetExceptionInformation())){

             ExitProcess(GetExceptionCode());

    //NOTE: We Never get here.

    }

    }

  • 相关阅读:
    AspNet Core 核心 通过依赖注入(注入服务)
    AspNetCore 中使用 InentityServer4(2)
    AspNetCore中使用Ocelot之 IdentityServer4(1)
    AspNetCore+Swagger 生成Model 描述
    scp带密码拷贝文件
    redis集群之节点少于六个错误-解决
    [AWS DA Guru] Serverless compute Exam Tips
    [AWS] Lambda Invocation types
    [AWS Developer Guru] CI/CD
    [AWS] Lab: CloudFormation nested stack
  • 原文地址:https://www.cnblogs.com/sevensd/p/5877754.html
Copyright © 2011-2022 走看看