吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 12207|回复: 1
收起左侧

[系统底层] 线程初始化过程 PK 加载DLL过程(详细)

  [复制链接]
fllc 发表于 2014-3-20 13:15
线程初始化过程 PK 加载DLL过程  :
//-------------------------------------------------------------------------------------------------------
//线程初始化过程:
//-------------------------------------------------------------------------------------------------------
7C92E450                         ; __stdcall KiUserApcDispatcher(x, x, x, x, x)
1.jpg

2.jpg

3.jpg

7C939962 E9 07 FF FF FF          jmp     __LdrpInitialize@12 ; _LdrpInitialize(x,x,x) //具体的实现代码在里面
//-------------------------------------------------------------------------------------------------------
__LdrpInitialize@12的大体流程:
__LdrpInitialize@12
{
  ...
  RtlEnterCriticalSection(&LdrpLoaderLock);
  if (Ldr == NULL)
  {
  call    _LdrpInitializeProcess@20
  }
  else
  {
  call    _LdrpInitializeThread@4 //↓↓↓解释
  }
  RtlLeaveCriticalSection(&LdrpLoaderLock);
  ...
}
//-------------------------------------------------------------------------------------------------------
_LdrpInitializeThread@4的大体流程:
_LdrpInitializeThread@4
{
  ...
  for (遍历Ldr链表)//以InMemoryOrderModuleList顺序
  {
  if ( !(Ldr->Flags & LDRP_DONT_CALL_FOR_THREADS) )//LDRP_DONT_CALL_FOR_THREADS被置位,就不会调用dll的oep和tls
  {
  if (Dll 有 tls)
  {
  LdrpCallTlsInitializers(LdrEntry->DllBase, DLL_THREAD_ATTACH);
  }
  LdrpCallInitRoutine(Ldr->EntryPoint, Ldr>DllBase, DLL_THREAD_ATTACH, NULL); //call dll的oep
  }   
  }
  if (exe 有 tls)
  {
  LdrpCallTlsInitializers(Peb->ImageBaseAddress, DLL_THREAD_ATTACH);
  }
  ...
}







//-------------------------------------------------------------------------------------------------------
__LdrpInitialize@12 的分析:
⒈RtlEnterCriticalSection(&LdrpLoaderLock); //LdrpLoaderLock是一个全局锁,此锁还在LdrpLoadDll函数里面使用,这会造成一些有意思的情况↓
                                         ① 在DllMain里面LoadLibrary会死锁,因为在DllMain未完成时,LdrpLoaderLock全局锁没释放,
    LoadLibrary内部又会调RtlEnterCriticalSection(&LdrpLoaderLock);完事之后就互相卡住了,
    LoadLibrary返回不了,DllMain就结束不了;反之DllMain结束不了,LoadLibrary也返回不了,
    缠缠绵绵,无限死锁!!!(MSDN没有解释死锁的原因)
     ② 如果想在DllMain里面CreateThread创个线程,并且不让DllMain返回(白利用的节奏,怎么白利用自己玩
        吧,说出来被开...),还是会出现被LdrpLoaderLock全局锁卡主的情况。不想被卡主可以自己主动释放掉
        这把锁,锁的位置在PEB+0x0A0偏移处(+0x0a0 LoaderLock       : Ptr32 Void),是在进程初始化的时候由
        全局变量LdrpLoaderLock赋给PEB+0x0A0的!!!
⒉在__LdrpInitialize@12 里面既有LdrpInitializeProcess,也有LdrpInitializeThread
  系统是根据PEB+0x0C(+0x00c Ldr              : Ptr32 _PEB_LDR_DATA)是否有指针,来决定调用LdrpInitializeProcess还是LdrpInitializeThread,
  进程初始化(第一个线程)时Ldr为NULL,此时会调用LdrpInitializeProcess;之后再创建线程时Ldr就不为NULL了,会调用LdrpInitializeThread。
⒊LdrpInitializeThread分析
  ①在LdrpInitializeThread里面,会遍历Ldr链表(以InMemoryOrderModuleList顺序)call每个Dll的tls回调(如果有)和EntryPoint,EntryPoint最终
    会call DllMain的DLL_THREAD_ATTACH,这里发现了一个有意思的Flags,LDRP_DONT_CALL_FOR_THREADS(0x0040000),
  在_LDR_DATA_TABLE_ENTRY.flags & LDRP_DONT_CALL_FOR_THREADS就不会调用指定Dll的DllMain(这是DisableThreadLibraryCalls 函数的基本原理)。
  ②call 完每个Dll的tls回调(如果有)和EntryPoint之后,会判断exe是否有tls,有的话会根据数据目录表的tls找到callback数组,
    按顺序call每个callback。
  ps:①有tls的exe,每创一个新线程都会调二次tls的回调(DLL_THREAD_ATTACH一次,DLL_THREAD_DETACH一次;新线程永不结束例外...);
      ②并且经测试,最初的进程初始化时,如果tls的第一次DLL_PROCESS_ATTACH失败(失败原因一般是进程还没初始化完成,某些dll的IAT未完成,
        call未完成的IAT会失败),会在DLL_PROCESS_DETACH的时候补一次tls的回调执行(进程初始化的tls只执行一次,DLL_PROCESS_ATTACH或
        DLL_PROCESS_DETACH;之后的新线程初始化时的tls会执行两次!!!)
    ③LdrpCallTlsInitializers内部call tls callback数组;LdrpCallInitRoutine 这个... (都是LdrpInitializeThread内部调的)

//-------------------------------------------------------------------------------------------------------
//Dll加载过程:
//-------------------------------------------------------------------------------------------------------
_LdrLoadDll@16的大体流程:_LdrLoadDll@16
{
  ...
  call    _LdrLockLoaderLock@12 //内部调用RtlEnterCriticalSection(&LdrpLoaderLock);
  call    _LdrpLoadDll@24 //↓↓↓解释
  call    _LdrUnlockLoaderLock@8//内部调用RtlLeaveCriticalSection(&LdrpLoaderLock);
  ...
}
//-------------------------------------------------------------------------------------------------------
_LdrpLoadDll@24的大体流程:
_LdrpLoadDll@24
{
  ...
  call    _LdrpMapDll@24//内部调NtCreateSection、NtMapViewOfSection;插入Ldr
  call    _LdrpRunInitializeRoutines@4//初始化;理论上只会调用新load的dll的tls(如果有)和oep,但是代码太风骚了,可以做手脚↓↓↓解释
  ...
}
//-------------------------------------------------------------------------------------------------------
_LdrpRunInitializeRoutines@4的大体流程:
_LdrpRunInitializeRoutines@4
{
  ...
  for(遍历Ldr链表) //InInitializationOrderModuleList顺序
  {
  if ( !(Ldr->Flags & LDRP_ENTRY_PROCESSED) )//没有LDRP_ENTRY_PROCESSED这个标志位的就放入数组中
  {
  存到一个数组中ArrayBug; //理论上如果我们自己没改过Ldr->Flags,那么这个遍历最终只会有一个Ldr放入数组中,那就是最新Load的
                          //那个dll的Ldr;但是我们可以把自己的dll(防别人注入的dll)去掉这个标志位!!!  
    }
  Ldr->Flags |= LDRP_ENTRY_PROCESSED;
  }
  for(循环遍历ArrayBug数组)
  {
  LdrpCallInitRoutine(EntryPoint, LdrEntry->DllBase, DLL_PROCESS_ATTACH, Context);
  }
  ...
}





//-------------------------------------------------------------------------------------------------------
LoadLibraryExW --->>> LdrLoadDll
⒈_LdrLoadDll@16的分析:
  ①LdrLockLoaderLock(1, 0, &v11); 内部调用了RtlEnterCriticalSection(&LdrpLoaderLock); 跟__LdrpInitialize@12里面共用一把锁
  ②_LdrLoadDll@16  ->  call    _LdrpLoadDll@24 ; LdrpLoadDll(x,x,x,x,x,x) //主要功能在_LdrpLoadDll@24内部实现
⒉_LdrpLoadDll@24 的分析:
  ①call    _LdrpMapDll@24  ; LdrpMapDll(x,x,x,x,x,x) //总体的作用就是把dll映射进进程的地址空间
  //内部的LdrpCreateDllSection是创建NtCreateSection创建区块对象;之后映射NtMapViewOfSection;
  //再然后是调用_LdrpAllocateDataTableEntry@4、_LdrpInsertMemoryTableEntry@4等操作把这个dll的_LDR_DATA_TABLE_ENTRY结构插入到Ldr链表里
  ②在映射完之后,就是对dll进行初始化,call    _LdrpRunInitializeRoutines@4 ; LdrpRunInitializeRoutines(x)
  内部会调用LdrpCallTlsInitializers(调用dll的tls回调,如果有的话)、LdrpCallInitRoutine(调用dll的EntryPoint)
  代码很风骚,具体自己结合od、IDA、reactos看吧,风骚大了就出问题了,有一个有意思的flags,LDRP_ENTRY_PROCESSED(0x0004000),如果把
  某个dll这个标志位去掉,那么当有dll加载时,被去掉LDRP_ENTRY_PROCESSED标志位的dll的oep就会先于要加载的dll的oep执行!!!
  这完全可以风骚的做到用自己的dll拦截其他人加载dll(XP下通过;Win7下如果只这样做,退出程序时会崩,发现是在ExitProcess前有 没有释放的内存,
  因为我们的dll等于是多次进入DLL_PROCESS_ATTACH初始化,办法我已经想到了,并且测试通过了,自己想办法吧,就是不让他申请那没用的内存就可以)
ps:LdrpRunInitializeRoutines函数的参数系统默认会传NULL,此时加载dll过程就不会调用dll的tls也不会调用exe的tls;
    如果传非NULL,代码貌似会执行dll的tls(如果有)和exe的tls(如果有)。





感觉有用的给个评分吧,谢谢鼓励。

x132627mw3qfn4en2f4tfn2.jpg.pagespeed.ic.xjcaw6SMqL.jpg

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

JoyChou 发表于 2014-3-20 13:26
好乱的感觉。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-24 09:09

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表