找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3917|回复: 9

【C语言】利用PEB和LDR遍历指定进程的模块

[复制链接]
发表于 2020-2-5 15:01:09 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
本程序理解上收到了群MinL同学的指导,非常感谢!

内核中PEB块和LDR链用处非常多,常见的用处比如就是本贴要讨论的遍历制定进程的模块;

实验环境:Visual Studio 2013,WDK8.1,Windows 7 x64虚拟机,Windbg,DbgView,KMDmanager。

首先我们用Windbg看一下EPROCESS,PEB在EPROCESS中是以PPEB指针形式作为成员变量的:
EPROCESS结构体:
  1. kd> dt _EPROCESS
  2. nt!_EPROCESS
  3.    +0x000 Pcb              : _KPROCESS
  4.    +0x160 ProcessLock      : _EX_PUSH_LOCK
  5.    +0x168 CreateTime       : _LARGE_INTEGER
  6.    +0x170 ExitTime         : _LARGE_INTEGER
  7.    +0x178 RundownProtect   : _EX_RUNDOWN_REF
  8.    +0x180 UniqueProcessId  : Ptr64 Void
  9.    +0x188 ActiveProcessLinks : _LIST_ENTRY
  10.    +0x198 ProcessQuotaUsage : [2] Uint8B
  11.    +0x1a8 ProcessQuotaPeak : [2] Uint8B
  12.    +0x1b8 CommitCharge     : Uint8B
  13.    +0x1c0 QuotaBlock       : Ptr64 _EPROCESS_QUOTA_BLOCK
  14.    +0x1c8 CpuQuotaBlock    : Ptr64 _PS_CPU_QUOTA_BLOCK
  15.    +0x1d0 PeakVirtualSize  : Uint8B
  16.    +0x1d8 VirtualSize      : Uint8B
  17.    +0x1e0 SessionProcessLinks : _LIST_ENTRY
  18.    +0x1f0 DebugPort        : Ptr64 Void
  19.    +0x1f8 ExceptionPortData : Ptr64 Void
  20.    +0x1f8 ExceptionPortValue : Uint8B
  21.    +0x1f8 ExceptionPortState : Pos 0, 3 Bits
  22.    +0x200 ObjectTable      : Ptr64 _HANDLE_TABLE
  23.    +0x208 Token            : _EX_FAST_REF
  24.    +0x210 WorkingSetPage   : Uint8B
  25.    +0x218 AddressCreationLock : _EX_PUSH_LOCK
  26.    +0x220 RotateInProgress : Ptr64 _ETHREAD
  27.    +0x228 ForkInProgress   : Ptr64 _ETHREAD
  28.    +0x230 HardwareTrigger  : Uint8B
  29.    +0x238 PhysicalVadRoot  : Ptr64 _MM_AVL_TABLE
  30.    +0x240 CloneRoot        : Ptr64 Void
  31.    +0x248 NumberOfPrivatePages : Uint8B
  32.    +0x250 NumberOfLockedPages : Uint8B
  33.    +0x258 Win32Process     : Ptr64 Void
  34.    +0x260 Job              : Ptr64 _EJOB
  35.    +0x268 SectionObject    : Ptr64 Void
  36.    +0x270 SectionBaseAddress : Ptr64 Void
  37.    +0x278 Cookie           : Uint4B
  38.    +0x27c UmsScheduledThreads : Uint4B
  39.    +0x280 WorkingSetWatch  : Ptr64 _PAGEFAULT_HISTORY
  40.    +0x288 Win32WindowStation : Ptr64 Void
  41.    +0x290 InheritedFromUniqueProcessId : Ptr64 Void
  42.    +0x298 LdtInformation   : Ptr64 Void
  43.    +0x2a0 Spare            : Ptr64 Void
  44.    +0x2a8 ConsoleHostProcess : Uint8B
  45.    +0x2b0 DeviceMap        : Ptr64 Void
  46.    +0x2b8 EtwDataSource    : Ptr64 Void
  47.    +0x2c0 FreeTebHint      : Ptr64 Void
  48.    +0x2c8 FreeUmsTebHint   : Ptr64 Void
  49.    +0x2d0 PageDirectoryPte : _HARDWARE_PTE
  50.    +0x2d0 Filler           : Uint8B
  51.    +0x2d8 Session          : Ptr64 Void
  52.    +0x2e0 ImageFileName    : [15] UChar
  53.    +0x2ef PriorityClass    : UChar
  54.    +0x2f0 JobLinks         : _LIST_ENTRY
  55.    +0x300 LockedPagesList  : Ptr64 Void
  56.    +0x308 ThreadListHead   : _LIST_ENTRY
  57.    +0x318 SecurityPort     : Ptr64 Void
  58.    +0x320 Wow64Process     : Ptr64 Void
  59.    +0x328 ActiveThreads    : Uint4B
  60.    +0x32c ImagePathHash    : Uint4B
  61.    +0x330 DefaultHardErrorProcessing : Uint4B
  62.    +0x334 LastThreadExitStatus : Int4B
  63.    +0x338 Peb              : Ptr64 _PEB
  64.    +0x340 PrefetchTrace    : _EX_FAST_REF
  65.    +0x348 ReadOperationCount : _LARGE_INTEGER
  66.    +0x350 WriteOperationCount : _LARGE_INTEGER
  67.    +0x358 OtherOperationCount : _LARGE_INTEGER
  68.    +0x360 ReadTransferCount : _LARGE_INTEGER
  69.    +0x368 WriteTransferCount : _LARGE_INTEGER
  70.    +0x370 OtherTransferCount : _LARGE_INTEGER
  71.    +0x378 CommitChargeLimit : Uint8B
  72.    +0x380 CommitChargePeak : Uint8B
  73.    +0x388 AweInfo          : Ptr64 Void
  74.    +0x390 SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
  75.    +0x398 Vm               : _MMSUPPORT
  76.    +0x420 MmProcessLinks   : _LIST_ENTRY
  77.    +0x430 HighestUserAddress : Ptr64 Void
  78.    +0x438 ModifiedPageCount : Uint4B
  79.    +0x43c Flags2           : Uint4B
  80.    +0x43c JobNotReallyActive : Pos 0, 1 Bit
  81.    +0x43c AccountingFolded : Pos 1, 1 Bit
  82.    +0x43c NewProcessReported : Pos 2, 1 Bit
  83.    +0x43c ExitProcessReported : Pos 3, 1 Bit
  84.    +0x43c ReportCommitChanges : Pos 4, 1 Bit
  85.    +0x43c LastReportMemory : Pos 5, 1 Bit
  86.    +0x43c ReportPhysicalPageChanges : Pos 6, 1 Bit
  87.    +0x43c HandleTableRundown : Pos 7, 1 Bit
  88.    +0x43c NeedsHandleRundown : Pos 8, 1 Bit
  89.    +0x43c RefTraceEnabled  : Pos 9, 1 Bit
  90.    +0x43c NumaAware        : Pos 10, 1 Bit
  91.    +0x43c ProtectedProcess : Pos 11, 1 Bit
  92.    +0x43c DefaultPagePriority : Pos 12, 3 Bits
  93.    +0x43c PrimaryTokenFrozen : Pos 15, 1 Bit
  94.    +0x43c ProcessVerifierTarget : Pos 16, 1 Bit
  95.    +0x43c StackRandomizationDisabled : Pos 17, 1 Bit
  96.    +0x43c AffinityPermanent : Pos 18, 1 Bit
  97.    +0x43c AffinityUpdateEnable : Pos 19, 1 Bit
  98.    +0x43c PropagateNode    : Pos 20, 1 Bit
  99.    +0x43c ExplicitAffinity : Pos 21, 1 Bit
  100.    +0x440 Flags            : Uint4B
  101.    +0x440 CreateReported   : Pos 0, 1 Bit
  102.    +0x440 NoDebugInherit   : Pos 1, 1 Bit
  103.    +0x440 ProcessExiting   : Pos 2, 1 Bit
  104.    +0x440 ProcessDelete    : Pos 3, 1 Bit
  105.    +0x440 Wow64SplitPages  : Pos 4, 1 Bit
  106.    +0x440 VmDeleted        : Pos 5, 1 Bit
  107.    +0x440 OutswapEnabled   : Pos 6, 1 Bit
  108.    +0x440 Outswapped       : Pos 7, 1 Bit
  109.    +0x440 ForkFailed       : Pos 8, 1 Bit
  110.    +0x440 Wow64VaSpace4Gb  : Pos 9, 1 Bit
  111.    +0x440 AddressSpaceInitialized : Pos 10, 2 Bits
  112.    +0x440 SetTimerResolution : Pos 12, 1 Bit
  113.    +0x440 BreakOnTermination : Pos 13, 1 Bit
  114.    +0x440 DeprioritizeViews : Pos 14, 1 Bit
  115.    +0x440 WriteWatch       : Pos 15, 1 Bit
  116.    +0x440 ProcessInSession : Pos 16, 1 Bit
  117.    +0x440 OverrideAddressSpace : Pos 17, 1 Bit
  118.    +0x440 HasAddressSpace  : Pos 18, 1 Bit
  119.    +0x440 LaunchPrefetched : Pos 19, 1 Bit
  120.    +0x440 InjectInpageErrors : Pos 20, 1 Bit
  121.    +0x440 VmTopDown        : Pos 21, 1 Bit
  122.    +0x440 ImageNotifyDone  : Pos 22, 1 Bit
  123.    +0x440 PdeUpdateNeeded  : Pos 23, 1 Bit
  124.    +0x440 VdmAllowed       : Pos 24, 1 Bit
  125.    +0x440 CrossSessionCreate : Pos 25, 1 Bit
  126.    +0x440 ProcessInserted  : Pos 26, 1 Bit
  127.    +0x440 DefaultIoPriority : Pos 27, 3 Bits
  128.    +0x440 ProcessSelfDelete : Pos 30, 1 Bit
  129.    +0x440 SetTimerResolutionLink : Pos 31, 1 Bit
  130.    +0x444 ExitStatus       : Int4B
  131.    +0x448 VadRoot          : _MM_AVL_TABLE
  132.    +0x488 AlpcContext      : _ALPC_PROCESS_CONTEXT
  133.    +0x4a8 TimerResolutionLink : _LIST_ENTRY
  134.    +0x4b8 RequestedTimerResolution : Uint4B
  135.    +0x4bc ActiveThreadsHighWatermark : Uint4B
  136.    +0x4c0 SmallestTimerResolution : Uint4B
  137.    +0x4c8 TimerResolutionStackRecord : Ptr64 _PO_DIAG_STACK_RECORD
复制代码


可以看到在x64中EPROCESS在0x338出的偏移(offset)是成员Peb(64位_PEB结构体指针),利用指针的偏移量即可获得PEB结构体指针的地址;

同样看一下在PEB结构体中:
  1. kd> dt _PEB
  2. nt!_PEB
  3.    +0x000 InheritedAddressSpace : UChar
  4.    +0x001 ReadImageFileExecOptions : UChar
  5.    +0x002 BeingDebugged    : UChar
  6.    +0x003 BitField         : UChar
  7.    +0x003 ImageUsesLargePages : Pos 0, 1 Bit
  8.    +0x003 IsProtectedProcess : Pos 1, 1 Bit
  9.    +0x003 IsLegacyProcess  : Pos 2, 1 Bit
  10.    +0x003 IsImageDynamicallyRelocated : Pos 3, 1 Bit
  11.    +0x003 SkipPatchingUser32Forwarders : Pos 4, 1 Bit
  12.    +0x003 SpareBits        : Pos 5, 3 Bits
  13.    +0x008 Mutant           : Ptr64 Void
  14.    +0x010 ImageBaseAddress : Ptr64 Void
  15.    +0x018 Ldr              : Ptr64 _PEB_LDR_DATA
  16.    +0x020 ProcessParameters : Ptr64 _RTL_USER_PROCESS_PARAMETERS
  17.    +0x028 SubSystemData    : Ptr64 Void
  18.    +0x030 ProcessHeap      : Ptr64 Void
  19.    +0x038 FastPebLock      : Ptr64 _RTL_CRITICAL_SECTION
  20.    +0x040 AtlThunkSListPtr : Ptr64 Void
  21.    +0x048 IFEOKey          : Ptr64 Void
  22.    +0x050 CrossProcessFlags : Uint4B
  23.    +0x050 ProcessInJob     : Pos 0, 1 Bit
  24.    +0x050 ProcessInitializing : Pos 1, 1 Bit
  25.    +0x050 ProcessUsingVEH  : Pos 2, 1 Bit
  26.    +0x050 ProcessUsingVCH  : Pos 3, 1 Bit
  27.    +0x050 ProcessUsingFTH  : Pos 4, 1 Bit
  28.    +0x050 ReservedBits0    : Pos 5, 27 Bits
  29.    +0x058 KernelCallbackTable : Ptr64 Void
  30.    +0x058 UserSharedInfoPtr : Ptr64 Void
  31.    +0x060 SystemReserved   : [1] Uint4B
  32.    +0x064 AtlThunkSListPtr32 : Uint4B
  33.    +0x068 ApiSetMap        : Ptr64 Void
  34.    +0x070 TlsExpansionCounter : Uint4B
  35.    +0x078 TlsBitmap        : Ptr64 Void
  36.    +0x080 TlsBitmapBits    : [2] Uint4B
  37.    +0x088 ReadOnlySharedMemoryBase : Ptr64 Void
  38.    +0x090 HotpatchInformation : Ptr64 Void
  39.    +0x098 ReadOnlyStaticServerData : Ptr64 Ptr64 Void
  40.    +0x0a0 AnsiCodePageData : Ptr64 Void
  41.    +0x0a8 OemCodePageData  : Ptr64 Void
  42.    +0x0b0 UnicodeCaseTableData : Ptr64 Void
  43.    +0x0b8 NumberOfProcessors : Uint4B
  44.    +0x0bc NtGlobalFlag     : Uint4B
  45.    +0x0c0 CriticalSectionTimeout : _LARGE_INTEGER
  46.    +0x0c8 HeapSegmentReserve : Uint8B
  47.    +0x0d0 HeapSegmentCommit : Uint8B
  48.    +0x0d8 HeapDeCommitTotalFreeThreshold : Uint8B
  49.    +0x0e0 HeapDeCommitFreeBlockThreshold : Uint8B
  50.    +0x0e8 NumberOfHeaps    : Uint4B
  51.    +0x0ec MaximumNumberOfHeaps : Uint4B
  52.    +0x0f0 ProcessHeaps     : Ptr64 Ptr64 Void
  53.    +0x0f8 GdiSharedHandleTable : Ptr64 Void
  54.    +0x100 ProcessStarterHelper : Ptr64 Void
  55.    +0x108 GdiDCAttributeList : Uint4B
  56.    +0x110 LoaderLock       : Ptr64 _RTL_CRITICAL_SECTION
  57.    +0x118 OSMajorVersion   : Uint4B
  58.    +0x11c OSMinorVersion   : Uint4B
  59.    +0x120 OSBuildNumber    : Uint2B
  60.    +0x122 OSCSDVersion     : Uint2B
  61.    +0x124 OSPlatformId     : Uint4B
  62.    +0x128 ImageSubsystem   : Uint4B
  63.    +0x12c ImageSubsystemMajorVersion : Uint4B
  64.    +0x130 ImageSubsystemMinorVersion : Uint4B
  65.    +0x138 ActiveProcessAffinityMask : Uint8B
  66.    +0x140 GdiHandleBuffer  : [60] Uint4B
  67.    +0x230 PostProcessInitRoutine : Ptr64     void
  68.    +0x238 TlsExpansionBitmap : Ptr64 Void
  69.    +0x240 TlsExpansionBitmapBits : [32] Uint4B
  70.    +0x2c0 SessionId        : Uint4B
  71.    +0x2c8 AppCompatFlags   : _ULARGE_INTEGER
  72.    +0x2d0 AppCompatFlagsUser : _ULARGE_INTEGER
  73.    +0x2d8 pShimData        : Ptr64 Void
  74.    +0x2e0 AppCompatInfo    : Ptr64 Void
  75.    +0x2e8 CSDVersion       : _UNICODE_STRING
  76.    +0x2f8 ActivationContextData : Ptr64 _ACTIVATION_CONTEXT_DATA
  77.    +0x300 ProcessAssemblyStorageMap : Ptr64 _ASSEMBLY_STORAGE_MAP
  78.    +0x308 SystemDefaultActivationContextData : Ptr64 _ACTIVATION_CONTEXT_DATA
  79.    +0x310 SystemAssemblyStorageMap : Ptr64 _ASSEMBLY_STORAGE_MAP
  80.    +0x318 MinimumStackCommit : Uint8B
  81.    +0x320 FlsCallback      : Ptr64 _FLS_CALLBACK_INFO
  82.    +0x328 FlsListHead      : _LIST_ENTRY
  83.    +0x338 FlsBitmap        : Ptr64 Void
  84.    +0x340 FlsBitmapBits    : [4] Uint4B
  85.    +0x350 FlsHighIndex     : Uint4B
  86.    +0x358 WerRegistrationData : Ptr64 Void
  87.    +0x360 WerShipAssertPtr : Ptr64 Void
  88.    +0x368 pContextData     : Ptr64 Void
  89.    +0x370 pImageHeaderHash : Ptr64 Void
  90.    +0x378 TracingFlags     : Uint4B
  91.    +0x378 HeapTracingEnabled : Pos 0, 1 Bit
  92.    +0x378 CritSecTracingEnabled : Pos 1, 1 Bit
  93.    +0x378 SpareTracingBits : Pos 2, 30 Bits
复制代码

可以看出,PEB结构体地址在0x018处偏移是指向了Ldr(_PEB_LDR_DATA结构体的64位指针),同样利用指针的偏移可以得到它,进一步看看_PEB_LDR_DATA这个结构图中有什么:

_PEB_LDR_DATA:
  1. kd> dt _PEB_LDR_DATA
  2. nt!_PEB_LDR_DATA
  3.    +0x000 Length           : Uint4B
  4.    +0x004 Initialized      : UChar
  5.    +0x008 SsHandle         : Ptr64 Void
  6.    +0x010 InLoadOrderModuleList : _LIST_ENTRY
  7.    +0x020 InMemoryOrderModuleList : _LIST_ENTRY
  8.    +0x030 InInitializationOrderModuleList : _LIST_ENTRY
  9.    +0x040 EntryInProgress  : Ptr64 Void
  10.    +0x048 ShutdownInProgress : UChar
  11.    +0x050 ShutdownThreadId : Ptr64 Void
复制代码


PEB_LDR_DATA中,在0x010偏移处可以得到InLoadOrderModuleList这个链表,是双向链表_LIST_ENTRY类型的,我们最后遍历这个LIST_ENTRY链表就可以了。

以下为代码实现,先说一下几个注意事项:

1.程序中需要利用PsLookupProcessByProcessId来获取制定进程的PERPROCESS,然后进行指针的偏移量计算来获得PEB, LDR以及最后的双向链表InLoadOrderModuleList,
其中比如我们第一次得到了PEPROCESS,将其转化为ULONG64类型的数,所做的(ULONG64)eproc + 0x338得到的是PEB结构体指针的地址,
所以我们如果要得到PEB结构体的指针(也就是说PEB结构体的地址)的话,需要再用“*”来取他的值,也就是这样:ULONG64 peb_addr = *(PULONG64)((ULONG64)eproc + 0x338);同理获得ldr结构体的地址也需要注意!

2.获取PEB结构体的地址可以使用API:PsGetProcessPeb,但是为了锻炼C语言指针的应用能力,本程序全部使用结构体指针的偏移来获取。

3.本程序用枚举当前虚拟机Win7 x64上的explorer.exe的模块为例,如果重复使用的话需要重新更新一下所要枚举的进程的当前句柄。

程序如下(C语言):
  1. #include <ntddk.h>
  2. #include <windef.h>

  3. #define PEB_OFFSET_IN_EPROCESS 0x338
  4. #define LDR_OFFSET_IN_PEB 0x018
  5. #define InLoadOrderModuleList_OFFSET 0x010


  6. typedef struct _LDR_DATA_TABLE_ENTRY
  7. {
  8.     LIST_ENTRY64    InLoadOrderLinks;
  9.     LIST_ENTRY64    InMemoryOrderLinks;
  10.     LIST_ENTRY64    InInitializationOrderLinks;
  11.     PVOID            DllBase;
  12.     PVOID            EntryPoint;
  13.     ULONG            SizeOfImage;
  14.     UNICODE_STRING    FullDllName;
  15.     UNICODE_STRING     BaseDllName;
  16.     ULONG            Flags;
  17.     USHORT            LoadCount;
  18.     USHORT            TlsIndex;
  19.     PVOID            SectionPointer;
  20.     ULONG            CheckSum;
  21.     PVOID            LoadedImports;
  22.     PVOID            EntryPointActivationContext;
  23.     PVOID            PatchInformation;
  24.     LIST_ENTRY64    ForwarderLinks;
  25.     LIST_ENTRY64    ServiceTagLinks;
  26.     LIST_ENTRY64    StaticLinks;
  27.     PVOID            ContextInformation;
  28.     ULONG64            OriginalBase;
  29.     LARGE_INTEGER    LoadTime;
  30. } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
  31. typedef struct _KAPC_STATE
  32. {
  33.     LIST_ENTRY ApcListHead[2];
  34.     PKPROCESS Process;
  35.     UCHAR KernelApcInProgress;
  36.     UCHAR KernelApcPending;
  37.     UCHAR UserApcPending;
  38. } KAPC_STATE, *PKAPC_STATE;

  39. // Functions declaration
  40. NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE ProcessId, PEPROCESS *Process);
  41. VOID KeStackAttachProcess(PRKPROCESS PROCESS,PKAPC_STATE ApcState);
  42. VOID KeUnstackDetachProcess(PKAPC_STATE ApcState);


  43. //
  44. // Get the pointer to the EPROCESS of the specific pid on the process.
  45. //
  46. PEPROCESS LookupProcess(HANDLE hPid)
  47. {
  48.     PEPROCESS eproc = NULL;
  49.     if (NT_SUCCESS(PsLookupProcessByProcessId(hPid, &eproc)))
  50.     {
  51.         return eproc;
  52.     }
  53.     return NULL;
  54. }



  55. // Enumerate the module of the specific process.
  56. VOID EnumerateModule(HANDLE hPid)
  57. {
  58.     KAPC_STATE ks;
  59.     PEPROCESS eproc = LookupProcess(hPid);
  60.     if (eproc == NULL)
  61.     {
  62.         DbgPrint("Can't find the EPROCESS...\n");
  63.         return;
  64.     }


  65.     __try
  66.     {
  67.         // Get the peb address, the PEB structure in the EPROCESS is a pointer to PEB, named PPEB.
  68.         // So the "(ULONG64)eproc + PEB_OFFSET_IN_EPROCESS" is the address the pointer to PEB.
  69.         // And finally, use the "*" to get the address to the PEB structure.
  70.         ULONG64 peb = *(PULONG64)((ULONG64)eproc + PEB_OFFSET_IN_EPROCESS);

  71.         KeStackAttachProcess(eproc, &ks);


  72.         // The LDR structure in PEB is also a pointer to PEB_LDR_DATA
  73.         // So, "(ULONG64)peb + LDR_OFFSET_IN_PEB" is the address of pointer to PEB_LDR_DATA.
  74.         // And the ULONG64 ldr is finally get the address of PEB_LDR_DATA structure.
  75.         ULONG64 ldr = *(PULONG64)((ULONG64)peb + LDR_OFFSET_IN_PEB);

  76.         // Get the address of "InLoadOrderModuleList" which in the PEB_LDR_DATA structure.
  77.         PLIST_ENTRY pListHead = (PLIST_ENTRY)(ldr + InLoadOrderModuleList_OFFSET);
  78.         PLIST_ENTRY pMod = pListHead->Flink;

  79.         while (pMod != pListHead)
  80.         {
  81.             DbgPrint("Base=%p, Size=%ld, Path=%wZ\n",
  82.                 (PVOID)(((PLDR_DATA_TABLE_ENTRY)pMod)->DllBase),
  83.                 (ULONG)(((PLDR_DATA_TABLE_ENTRY)pMod)->SizeOfImage),
  84.                 &(((PLDR_DATA_TABLE_ENTRY)pMod)->FullDllName));
  85.             pMod = pMod->Flink;
  86.         }
  87.     }
  88.     __except (EXCEPTION_EXECUTE_HANDLER)
  89.     {
  90.         DbgPrint("EXCEPTION_EXECUTE_HANDLER is occure...\n");
  91.     }
  92.     KeUnstackDetachProcess(&ks);
  93. }


  94. VOID DriverUnload(IN PDRIVER_OBJECT pDrvObj)
  95. {
  96.     DbgPrint("DriverUnload...\n");
  97. }

  98. NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDrvObj, IN PUNICODE_STRING RegistryPath)
  99. {
  100.     DbgPrint("DriverEntry...\n");
  101.     pDrvObj->DriverUnload = DriverUnload;

  102.     EnumerateModule((HANDLE)1320);        // explorer.exe's current handle pid.

  103.     return STATUS_SUCCESS;
  104. }
复制代码


运行结果(只显示一部分结果了哈):
无标题.png

本贴用作学习笔记用于记录遇到的错误和解决方法,便于大家交流讨论和之后的温习。

有关PEB,LDR的只是可以参考一下站里的帖子:
https://www.0xaa55.com/forum.php ... 5&highlight=LDR
https://www.0xaa55.com/forum.php ... 3&highlight=PEB
回复

使用道具 举报

发表于 2020-2-5 22:57:48 | 显示全部楼层
继续纠结几个细节问题:
1. Lookup的本质是一个引用,你可能忘记了或者不知到要解引用进程对象(ObDereferenceObject)。
2. 获取PEB用硬编码是一种很蛋疼的行为。有个函数叫PsGetProcessPeb,你反汇编这个函数后就可以发现这个偏移量就在函数里。
每个版本的同一体系架构的Windows这个函数都长一个德行。比如x64上它们都长这样:
  1. mov rax,qword ptr[rcx+xxx]
  2. ret
复制代码

机器码就是48 8B 81 XX XX XX XX C3。那么函数地址+3的4个字节就是偏移量了。
3. PEB和LDR都在用户态内存中,你可以试试写个应用程序。用ZwQueryInformationProcess函数可以拿到PEB,然后再用读进程内存的函数枚举。
4. LDR是一个双向链表,你可以试试摘链隐藏模块,并恢复。如果ARK工具(比如PCHunter)枚举出的模块标红就证明隐藏成功。
5. 你特地声明的三个函数都是已经在MSDN中文档化的函数,它们被包含在了ntifs.h里。可以认为ntifs.h>ntddk.h>wdm.h。
6. 读写进程内存的话使用try-except是给ProbeForRead/Write函数用的,否则try就没什么用,异常也不会进入except里,这是内核try特色。ProbeForRead/Write也是文档化函数,自己查MSDN怎么用吧。
回复 赞! 1 靠! 0

使用道具 举报

 楼主| 发表于 2020-2-6 01:13:44 | 显示全部楼层
tangptr@126.com 发表于 2020-2-5 22:57
继续纠结几个细节问题:
1. Lookup的本质是一个引用,你可能忘记了或者不知到要解引用进程对象(ObDerefere ...

PsGetProcessPeb的反汇编的确是那样的,在我的虚拟机上是 mov rax, qword ptr [rcx + 338h],正好就是PEB在EPROCESS中的偏移量;
那个这个程序的整体结构是参考Tesla_Angela大佬的那个PDF上的,我认为那个ProbeForRead没有什么实质性的帮助所以当初自己复述程序时候就没有考虑到,看来还是有区别的。
2,3,4的练习我会自己试着写一下!当初写头文件的时候,我在提前include了wdm.h,后来在他下面包含了ntifs.h头文件,结果程序划红线(有错误),我就去掉了ntifs.h头文件,直到包含了ntddk.h头文件,现在才晓得是这样的一个包含顺序!学习了,谢谢tangptr大佬的指导!orz
回复 赞! 靠!

使用道具 举报

发表于 2020-2-6 04:11:43 | 显示全部楼层
本帖最后由 Ayala 于 2020-2-6 13:40 编辑

都Attach了后面直接get就好了
https://docs.microsoft.com/en-us ... estackattachprocess
另外硬编码结构偏移不太好吧,汇编现在几乎都不这么写了 自己定义一个简单的结构呢不用的成员忽略了就好了
回复 赞! 靠!

使用道具 举报

发表于 2020-2-6 13:38:35 | 显示全部楼层
watermelon 发表于 2020-2-6 01:13
PsGetProcessPeb的反汇编的确是那样的,在我的虚拟机上是 mov rax, qword ptr [rcx + 338h],正好就是PEB ...

再说一点,直接对进程对象搞操作的过程要防止进程突然退出。
进程对象有个锁用来防止进程突然退出,它是Process->RundownProtect。用ExAcquireRundownProtection可以获取锁,用ExReleaseRundownProtection可以释放锁。这些都是导出的函数,不过用这两个操作进程防退出锁需要搞偏移量。
从NT6开始用PsAcquireProcessExitSynchronization/PsReleaseProcessExitSynchronization也可以操作进程防退出锁。参数直接填进程对象地址就行。
如果用ZwXXX函数的话(也就是用句柄操作进程对象)这些操作都被包含了。
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2020-2-7 19:07:33 | 显示全部楼层
本帖最后由 watermelon 于 2020-2-7 20:18 编辑
tangptr@126.com 发表于 2020-2-5 22:57
继续纠结几个细节问题:
1. Lookup的本质是一个引用,你可能忘记了或者不知到要解引用进程对象(ObDerefere ...


收获超级多!
1.小弟我一开始的确不知道用了PsLookupProcessByProcessId以后要再解引用,然后我又查了一遍这个API的文档,发现了人家说的非常清楚:
2020-02-07_185255.png
2.我在vs2013和wdk8.1上用了ntifs的头文件,但是还是要声明_LDR_DATA_TABLE_ENTRY这个结构体。
3.成功完成了“摘链”的操作,用来移除模块(PChunter64上的确有明确的标记为红色的,并且在最下面):
捕获.PNG
一开始我摘链的时候还以为只需要将InLoadOrderModuleList的模块的链表结点去除掉就行,但是不成功,PCHunter64上只会将那个链表结点放在最后一个位置,而不是原先的位置;
后来我上网查了一下,发现有一篇帖子是win32上操作的,他将InLoadOrderModuleList、InMemoryOrderModuleList、InInitializationOrderModuleList三个链表全部改变了。
经过几次实验发现,InLoadOrderModuleList、InMemoryOrderModuleList、InInitializationOrderModuleList里面模块的顺序是一样的(多次通过打印_PEB_LDR_DATA中偏移0x010,
0x020,0x030位置处的结构体),所以每次我就按照InLoadOrderModuleList的顺序来找指定的要脱链模块的位置,然后三个链表同时进行改变。
最后是一个摘链以后怎么恢复,我是想的用一个全局变量的结构体来存储当初被摘链的模块在链表上的信息(包括他的地址和他在原先链表上的位置信息),然后进行双向链表的插入操作,
我用windbg调试程序,发现程序每次可以单步运行到末尾,但是程序一运行完毕就会蓝屏,可能是我在当时恢复链表信息的时候姿势不对(我猜是我的恢复时候链表的结点的内容没有写对),
此时需要进一步调试程序。

  1. // Remove and recover module test.
  2. #include <ntddk.h>
  3. #include <windef.h>


  4. // _KAPC_STATE structure is included in "ntifs.h" header file.
  5. typedef struct _KAPC_STATE
  6. {
  7.         LIST_ENTRY ApcListHead[2];
  8.         PKPROCESS Process;
  9.         UCHAR KernelApcInProgress;
  10.         UCHAR KernelApcPending;
  11.         UCHAR UserApcPending;
  12. } KAPC_STATE, *PKAPC_STATE;

  13. typedef struct _LDR_DATA_TABLE_ENTRY
  14. {
  15.         LIST_ENTRY64        InLoadOrderLinks;
  16.         LIST_ENTRY64        InMemoryOrderLinks;
  17.         LIST_ENTRY64        InInitializationOrderLinks;
  18.         PVOID                        DllBase;
  19.         PVOID                        EntryPoint;
  20.         ULONG                        SizeOfImage;
  21.         UNICODE_STRING        FullDllName;
  22.         UNICODE_STRING         BaseDllName;
  23.         ULONG                        Flags;
  24.         USHORT                        LoadCount;
  25.         USHORT                        TlsIndex;
  26.         PVOID                        SectionPointer;
  27.         ULONG                        CheckSum;
  28.         PVOID                        LoadedImports;
  29.         PVOID                        EntryPointActivationContext;
  30.         PVOID                        PatchInformation;
  31.         LIST_ENTRY64        ForwarderLinks;
  32.         LIST_ENTRY64        ServiceTagLinks;
  33.         LIST_ENTRY64        StaticLinks;
  34.         PVOID                        ContextInformation;
  35.         ULONG64                        OriginalBase;
  36.         LARGE_INTEGER        LoadTime;
  37. } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

  38. //
  39. // Functions declaration
  40. //
  41. NTKERNELAPI PPEB PsGetProcessPeb(PEPROCESS Process);
  42. NTKERNELAPI NTSTATUS PsLookupProcessByProcessId(HANDLE Id, PEPROCESS *Process);
  43. NTKERNELAPI VOID NTAPI KeStackAttachProcess(PEPROCESS Process, PKAPC_STATE ApcState);
  44. NTKERNELAPI VOID NTAPI KeUnstackDetachProcess(PKAPC_STATE ApcState);


  45. // Use the pointer of LIST_ENTRY to store the message
  46. // about removed/recovered module.
  47. typedef struct _RECOVER_MODULE
  48. {
  49.         PLIST_ENTRY module;
  50.         INT position;
  51. }RECOVER_MODULE, *PRECOVER_MODULE;


  52. // define a global RECOVER_MODULE structure parameter.
  53. RECOVER_MODULE g_RecoverMod = { 0 };


  54. //
  55. // Get the process's pointer to EPROCESS.
  56. //
  57. PEPROCESS LookupProcess(IN HANDLE hPid)
  58. {
  59.         PEPROCESS eproc = NULL;
  60.         if (NT_SUCCESS(PsLookupProcessByProcessId(hPid, &eproc)))
  61.         {
  62.                 return eproc;
  63.         }
  64.         return NULL;
  65. }


  66. //
  67. // Remove the module.
  68. //
  69. VOID RemoveModule(IN HANDLE hPid, IN UNICODE_STRING usModName, IN OUT PRECOVER_MODULE pRecoverMod)
  70. {
  71.         DbgPrint("RemoveModule...\n");
  72.         PEPROCESS eproc = LookupProcess(hPid);
  73.         KAPC_STATE ks;
  74.         INT index = 0;
  75.         if (eproc)
  76.         {
  77.                 DbgPrint("Get the valid EPROCESS's address...\n");
  78.         }
  79.         else
  80.         {
  81.                 DbgPrint("Can't get the valid EPROCESS's address...\n");
  82.                 return;
  83.         }

  84.         // Attach the process.
  85.         KeStackAttachProcess(eproc, &ks);

  86.         // Get the address of PEB.
  87.         ULONG64 peb = (ULONG64)PsGetProcessPeb(eproc);

  88.         // Get the address of LDR.
  89.         ULONG64 ldr = *(PULONG64)((ULONG64)peb + 0x018);

  90.        
  91.         // Get the address of "InLoadOrderModuleList".
  92.         PLIST_ENTRY pLoadListHead = (PLIST_ENTRY)(ldr + 0x010);                // 0x010 is the offset.
  93.         PLIST_ENTRY pLoadMod = pLoadListHead->Flink;

  94.         // Get the address of "InMemoryOrderModuleList".
  95.         PLIST_ENTRY pMemListHead = (PLIST_ENTRY)(ldr + 0x020);                // 0x020 is the offset
  96.         PLIST_ENTRY pMemMod = pMemListHead->Flink;

  97.         // Get the address of "InInitializationOrderModuleList".
  98.         PLIST_ENTRY pInitListHead = (PLIST_ENTRY)(ldr + 0x030);                // 0x030 is the offset
  99.         PLIST_ENTRY pInitMod = pInitListHead->Flink;


  100.         // Try to remove the module.
  101.         while (pLoadMod != pLoadListHead)
  102.         {
  103.                 if (RtlEqualUnicodeString(&usModName, &(((PLDR_DATA_TABLE_ENTRY)pLoadMod)->BaseDllName), TRUE))
  104.                 {
  105.                         DbgPrint("Find the module:%wZ\n", &usModName);

  106.                         // Remove the module on "InLoadOrderModuleList".
  107.                         pLoadMod->Blink->Flink = pLoadMod->Flink;
  108.                         pLoadMod->Flink->Blink = pLoadMod->Blink;

  109.                         // Remove the module on "InMemoryOrderModuleList".
  110.                         pMemMod->Blink->Flink = pMemMod->Flink;
  111.                         pMemMod->Flink->Blink = pMemMod->Blink;
  112.                        
  113.                         // Remove the module on "InInitializationOrderModuleList".
  114.                         pInitMod->Blink->Flink = pInitMod->Flink;
  115.                         pInitMod->Flink->Blink = pInitMod->Blink;

  116.                         // Store the message of the removed module.
  117.                         pRecoverMod->module = (PLIST_ENTRY)ExAllocatePool(PagedPool, sizeof(LIST_ENTRY));
  118.                         RtlMoveMemory(pRecoverMod->module, pLoadMod, sizeof(LIST_ENTRY));
  119.                         pRecoverMod->position = index;                // Store the position of the removed module.

  120.                         DbgPrint("Modified the module's successfully...\n");
  121.                         break;
  122.                 }
  123.                
  124.                 pLoadMod = pLoadMod->Flink;
  125.                 pMemMod = pMemMod->Flink;
  126.                 pInitMod = pInitMod->Flink;
  127.                 index++;
  128.         }
  129.        
  130.         // Detach the process.
  131.         KeUnstackDetachProcess(&ks);

  132.         // Release the resource which caused by "PsLookupProcessByProcessId".
  133.         ObDereferenceObject(eproc);
  134. }

  135. //
  136. // Recover the module which has been removed.
  137. // WARNING: this function can be operated successfully, but , maybe some structures
  138. // of LDR that I have made a mistake. So, when use this function, the computer can
  139. // corrupt suddenly.
  140. //
  141. VOID RecoverModule(IN HANDLE hPid, IN RECOVER_MODULE RecoverModule)
  142. {
  143.         PEPROCESS eproc = LookupProcess(hPid);
  144.         KAPC_STATE ks;
  145.         INT index = 0;

  146.         // address of PEB structure.
  147.         ULONG64 peb = (ULONG64)PsGetProcessPeb(eproc);
  148.         // attach the process.
  149.         KeStackAttachProcess(eproc, &ks);

  150.         // address of LDR structure.
  151.         ULONG64 ldr = *(PULONG64)(peb + 0x018);                // 0x018 is the offset.



  152.         // Get the address of "InLoadOrderModuleList".
  153.         PLIST_ENTRY pLoadListHead = (PLIST_ENTRY)(ldr + 0x010);                // 0x010 is the offset.
  154.         PLIST_ENTRY pLoadMod = pLoadListHead->Flink;

  155.         // Get the address of "InMemoryOrderModuleList".
  156.         PLIST_ENTRY pMemListHead = (PLIST_ENTRY)(ldr + 0x020);                // 0x020 is the offset
  157.         PLIST_ENTRY pMemMod = pMemListHead->Flink;

  158.         // Get the address of "InInitializationOrderModuleList".
  159.         PLIST_ENTRY pInitListHead = (PLIST_ENTRY)(ldr + 0x030);                // 0x030 is the offset
  160.         PLIST_ENTRY pInitMod = pInitListHead->Flink;

  161.         while (pLoadMod != pLoadListHead)
  162.         {
  163.                 DbgPrint("Inner cycle!!!...\n");
  164.                 if (index == RecoverModule.position)
  165.                 {
  166.                         PLIST_ENTRY temp;

  167.                         RECOVER_MODULE RecoverModule_1 = { 0 };
  168.                         RECOVER_MODULE RecoverModule_2 = { 0 };

  169.                         RecoverModule_1.module = (PLIST_ENTRY)ExAllocatePool(PagedPool, sizeof(LIST_ENTRY));
  170.                         RecoverModule_2.module = (PLIST_ENTRY)ExAllocatePool(PagedPool, sizeof(LIST_ENTRY));

  171.                         // Make two duplications of "pRecoverModule".
  172.                         RtlMoveMemory(RecoverModule_1.module, RecoverModule.module, sizeof(LIST_ENTRY));
  173.                         RtlMoveMemory(RecoverModule_2.module, RecoverModule.module, sizeof(LIST_ENTRY));


  174.                         // Recover the "InLoadOrderModuleList".
  175.                         temp = pLoadMod->Flink;
  176.                         pLoadMod->Flink = RecoverModule.module;
  177.                         RecoverModule.module->Flink = temp;
  178.                         temp->Blink = RecoverModule.module;
  179.                         RecoverModule.module->Blink = pLoadMod;

  180.                         // Recover the "InMemoryOrderModuleList".
  181.                         temp = pMemMod->Flink;
  182.                         pMemMod->Flink = RecoverModule_1.module;
  183.                         RecoverModule_1.module->Flink = temp;
  184.                         temp->Blink = RecoverModule_1.module;
  185.                         RecoverModule_1.module->Blink = pMemMod;

  186.                         // Recover the "InInitializationOrderModuleList"
  187.                         temp = pInitMod->Flink;
  188.                         pInitMod->Flink = RecoverModule_2.module;
  189.                         RecoverModule_2.module->Flink = temp;
  190.                         temp->Blink = RecoverModule_2.module;
  191.                         RecoverModule_2.module->Blink = pMemMod;

  192.                         break;
  193.                 }

  194.                 // Because of the structure's content, "pRecoverModule_1" and
  195.                 // "pRecoverModule_2" can't be free.
  196.                 // ExFreePool(pRecoverModule_1);
  197.                 // ExFreePool(pRecoverModule_2);

  198.                 pLoadMod = pLoadMod->Flink;
  199.                 pMemMod = pMemMod->Flink;
  200.                 pInitMod = pInitMod->Flink;
  201.                 index++;
  202.         }
  203.         ObDereferenceObject(eproc);
  204. }


  205. VOID DriverUnload(IN PDRIVER_OBJECT pDrvObj)
  206. {
  207.         DbgPrint("DriverUnload...\n");
  208.         // Release the allocated buffer of "g_RecoverMod.module".
  209.         ExFreePool(g_RecoverMod.module);
  210. }

  211. NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDrvObj, IN PUNICODE_STRING RegistryPath)
  212. {
  213.         DbgPrint("DriverEntry...\n");
  214.         pDrvObj->DriverUnload = DriverUnload;

  215.         // The name of module which you want to remove.
  216.         UNICODE_STRING usModName;

  217.         // Try to remove the kernel32.dll of the "explorer.exe".
  218.         RtlInitUnicodeString(&usModName, L"kernel32.dll");

  219.         RemoveModule((HANDLE)1520, usModName, &g_RecoverMod);

  220.         //RecoverModule((HANDLE)1396, g_RecoverMod);
  221.        
  222.         return STATUS_SUCCESS;

  223. }
复制代码


接下来需要接着调试程序和完成Ring3上面ZwQueryInformationProcess的PEB操作。
Or2
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2020-2-7 20:17:09 | 显示全部楼层
Ayala 发表于 2020-2-6 04:11
都Attach了后面直接get就好了
https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-n ...

哦,就是用自己声明一下的结构体,然后用->操作来写是嘛,那样也是一个非常不错的办法!orz
回复 赞! 靠!

使用道具 举报

发表于 2020-2-9 01:42:53 | 显示全部楼层
楼主试试把PEB32也给枚举出来,提示:Wow64Process是PEB32的指针,用PsGetProcessWow64Process获取。
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2020-3-13 17:09:03 | 显示全部楼层
美俪女神 发表于 2020-2-9 01:42
楼主试试把PEB32也给枚举出来,提示:Wow64Process是PEB32的指针,用PsGetProcessWow64Process获取。 ...

哦哦好的!!超感谢“美丽女神“管理员的指导!
小弟我试试。
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-12-22 16:28 , Processed in 0.037659 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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