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

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

2014-3-20 11:51
25926

线程初始化过程 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下还要改一下  


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

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

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

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

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

接着潜了

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

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

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

我还是把那段删了为好
2014-3-23 23:08
0
游客
登录 | 注册 方可回帖
返回
//