首页
社区
课程
招聘
[原创]线程初始化过程 PK 加载DLL过程(详细)
2014-3-20 11:51 24997

[原创]线程初始化过程 PK 加载DLL过程(详细)

2014-3-20 11:51
24997
线程初始化过程 PK 加载DLL过程 :
//-------------------------------------------------------------------------------------------------------
//线程初始化过程:
//-------------------------------------------------------------------------------------------------------
7C92E450 ; __stdcall KiUserApcDispatcher(x, x, x, x, x)

7C92E455 FF D0 call eax //这里eax是LdrInitializeThunk函数地址
//-------------------------------------------------------------------------------------------------------


//-------------------------------------------------------------------------------------------------------


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里面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(如果有)。

//-------------------------------------------------------------------------------------------------------







Release.zip
↑↑↑先于要加载的dll弹框

xp,win7都通过,当然win7下还要改一下  

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

上传的附件:
收藏
点赞1
打赏
分享
最新回复 (41)
雪    币: 185
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
whnet 2014-3-20 12:02
2
0
先MARK再看。 料挺足啊
雪    币: 90
活跃值: (80)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
hulucc 2014-3-20 12:21
3
0
一直不理解为什么dllmain里不能调用loadlibrary和createthread
这里看来有详细的答案

话说白利用是什么?
雪    币: 3640
活跃值: (3813)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
caolinkai 2014-3-20 14:03
4
0
果然风骚。。。。。。。
雪    币: 79
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
silence刘 2014-3-20 14:05
5
0
mark一下
雪    币: 70
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yxhbboy 2014-3-20 14:31
6
0
表示膜拜下!但给我感受最多的还是“办法我已经想到了,自己想办法吧”。
雪    币: 8861
活跃值: (2364)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 10 2014-3-21 10:26
7
0
我补充一下是怎么解决,DLLMain重入的吧。

其实随便一个空DLL,导出一个接口可以获得DLLMain函数的地址,然后在exe里加载完这个DLL后hook一下这个DLL的DLLMain跳入检测函数就好了~~

没想到这个也被公开了~
雪    币: 281
活跃值: (28)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
aiwuxian 1 2014-3-21 21:46
8
0
以后不发了  

接着潜了

今天又发现一个利用打印机服务进程 LPC把驱动加载上的 很风骚...
雪    币: 272
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
AASSMM 2014-3-21 21:57
9
0
DLLMain里面是可以loadlibrary的,但是有条件,加载的DLL的导入函数不能重复。
雪    币: 281
活跃值: (28)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
aiwuxian 1 2014-3-21 22:54
10
0
难道是我代码看的不仔细,接着修炼了
雪    币: 8861
活跃值: (2364)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 10 2014-3-22 01:02
11
0
好古老的样子,貌似在什么东西里看到过。
雪    币: 39
活跃值: (158)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
syskeylbz 2014-3-22 01:51
12
0
今晚夜深了,mark一下,有时间学习
雪    币: 95
活跃值: (119)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
JingSao 2014-3-22 08:43
13
0
只能表示膜拜了
雪    币: 218
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
誓言剑 2014-3-22 09:45
14
0
我太他妈喜欢说话说一半的人了
雪    币: 11
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
SinCoder 2014-3-22 11:10
15
0
想起了那个 DropSploit
雪    币: 119
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
libocdf 2014-3-22 11:38
16
0
总结呢?最后总结呢?赶紧写一份交上来!
雪    币: 8861
活跃值: (2364)
能力值: ( LV12,RANK:760 )
在线值:
发帖
回帖
粉丝
cvcvxk 10 2014-3-22 12:39
17
0
对,就是这个东西。
雪    币: 281
活跃值: (28)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
aiwuxian 1 2014-3-22 12:53
18
0
我才疏学浅了  

第一次玩那个
雪    币: 1227
活跃值: (907)
能力值: ( LV12,RANK:750 )
在线值:
发帖
回帖
粉丝
boywhp 12 2014-3-22 15:55
19
0
我居然没注意看到DropSploit,浪费了那个1G的源码了,有空研究下
雪    币: 281
活跃值: (28)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
aiwuxian 1 2014-3-22 16:56
20
0
额 我刚下的Carberp全部100多M,哪里有1G的源码,告诉我也提高下

之前是玩一个exe病毒这样加载的驱动
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
luzhenjun 2014-3-22 17:34
21
0
MARK
雪    币: 882
活跃值: (350)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zquchs 2014-3-22 22:47
22
0
强帖,膜拜一下
雪    币: 1227
活跃值: (907)
能力值: ( LV12,RANK:750 )
在线值:
发帖
回帖
粉丝
boywhp 12 2014-3-23 20:14
23
0
https://github.com/hzeroo/Carberp
雪    币: 55
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
AmaranthF 2014-3-23 21:18
24
0
我写的在dllmain里面loadlibrary的程序在几千人电脑上用也没见过死锁……
雪    币: 281
活跃值: (28)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
aiwuxian 1 2014-3-23 23:08
25
0
好吧,我的意思是在进程初始化时 load dll的一些风骚用法的时候出现的小概率情况

我还是把那段删了为好
游客
登录 | 注册 方可回帖
返回