PEB结构(Process Envirorment Block Structure)其中文名是进程环境块信息,进程环境块内部包含了进程运行的详细参数信息,每一个进程在运行后都会存在一个特有的PEB结构,通过附加进程并遍历这段结构即可得到非常多的有用信息。
在应用层下,如果想要得到PEB的基地址只需要取fs:[0x30]即可,TEB线程环境块则是fs:[0x18],如果在内核层想要得到应用层进程的PEB信息我们需要调用特定的内核函数来获取,如下案例将教大家如何在内核层取到应用层进程的PEB结构。
首先在开始写代码之前需要先定义好PEB进程环境快结构体,用于对内存指针解析,新建peb.h文件并保存如下代码,这些是微软的结构定义分为32位与64位,官方定义规范而已不需要费工夫。
#pragma once
#include <ntifs.h>
typedef struct _CURDIR // 2 elements, 0x18 bytes (sizeof)
{
/*0x000*/ struct _UNICODE_STRING DosPath; // 3 elements, 0x10 bytes (sizeof)
/*0x010*/ VOID* Handle;
}CURDIR, *PCURDIR;
typedef struct _RTL_DRIVE_LETTER_CURDIR // 4 elements, 0x18 bytes (sizeof)
{
/*0x000*/ UINT16 Flags;
/*0x002*/ UINT16 Length;
/*0x004*/ ULONG32 TimeStamp;
/*0x008*/ struct _STRING DosPath; // 3 elements, 0x10 bytes (sizeof)
}RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
typedef enum _SYSTEM_DLL_TYPE // 7 elements, 0x4 bytes
{
PsNativeSystemDll = 0 /*0x0*/,
PsWowX86SystemDll = 1 /*0x1*/,
PsWowArm32SystemDll = 2 /*0x2*/,
PsWowAmd64SystemDll = 3 /*0x3*/,
PsWowChpeX86SystemDll = 4 /*0x4*/,
PsVsmEnclaveRuntimeDll = 5 /*0x5*/,
PsSystemDllTotalTypes = 6 /*0x6*/
}SYSTEM_DLL_TYPE, *PSYSTEM_DLL_TYPE;
typedef struct _EWOW64PROCESS // 3 elements, 0x10 bytes (sizeof)
{
/*0x000*/ VOID* Peb;
/*0x008*/ UINT16 Machine;
/*0x00A*/ UINT8 _PADDING0_[0x2];
/*0x00C*/ enum _SYSTEM_DLL_TYPE NtdllType;
}EWOW64PROCESS, *PEWOW64PROCESS;
typedef struct _RTL_USER_PROCESS_PARAMETERS // 37 elements, 0x440 bytes (sizeof)
{
/*0x000*/ ULONG32 MaximumLength;
/*0x004*/ ULONG32 Length;
/*0x008*/ ULONG32 Flags;
/*0x00C*/ ULONG32 DebugFlags;
/*0x010*/ VOID* ConsoleHandle;
/*0x018*/ ULONG32 ConsoleFlags;
/*0x01C*/ UINT8 _PADDING0_[0x4];
/*0x020*/ VOID* StandardInput;
/*0x028*/ VOID* StandardOutput;
/*0x030*/ VOID* StandardError;
/*0x038*/ struct _CURDIR CurrentDirectory; // 2 elements, 0x18 bytes (sizeof)
/*0x050*/ struct _UNICODE_STRING DllPath; // 3 elements, 0x10 bytes (sizeof)
/*0x060*/ struct _UNICODE_STRING ImagePathName; // 3 elements, 0x10 bytes (sizeof)
/*0x070*/ struct _UNICODE_STRING CommandLine; // 3 elements, 0x10 bytes (sizeof)
/*0x080*/ VOID* Environment;
/*0x088*/ ULONG32 StartingX;
/*0x08C*/ ULONG32 StartingY;
/*0x090*/ ULONG32 CountX;
/*0x094*/ ULONG32 CountY;
/*0x098*/ ULONG32 CountCharsX;
/*0x09C*/ ULONG32 CountCharsY;
/*0x0A0*/ ULONG32 FillAttribute;
/*0x0A4*/ ULONG32 WindowFlags;
/*0x0A8*/ ULONG32 ShowWindowFlags;
/*0x0AC*/ UINT8 _PADDING1_[0x4];
/*0x0B0*/ struct _UNICODE_STRING WindowTitle; // 3 elements, 0x10 bytes (sizeof)
/*0x0C0*/ struct _UNICODE_STRING DesktopInfo; // 3 elements, 0x10 bytes (sizeof)
/*0x0D0*/ struct _UNICODE_STRING ShellInfo; // 3 elements, 0x10 bytes (sizeof)
/*0x0E0*/ struct _UNICODE_STRING RuntimeData; // 3 elements, 0x10 bytes (sizeof)
/*0x0F0*/ struct _RTL_DRIVE_LETTER_CURDIR CurrentDirectores[32];
/*0x3F0*/ UINT64 EnvironmentSize;
/*0x3F8*/ UINT64 EnvironmentVersion;
/*0x400*/ VOID* PackageDependencyData;
/*0x408*/ ULONG32 ProcessGroupId;
/*0x40C*/ ULONG32 LoaderThreads;
/*0x410*/ struct _UNICODE_STRING RedirectionDllName; // 3 elements, 0x10 bytes (sizeof)
/*0x420*/ struct _UNICODE_STRING HeapPartitionName; // 3 elements, 0x10 bytes (sizeof)
/*0x430*/ UINT64* DefaultThreadpoolCpuSetMasks;
/*0x438*/ ULONG32 DefaultThreadpoolCpuSetMaskCount;
/*0x43C*/ UINT8 _PADDING2_[0x4];
}RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
typedef struct _PEB_LDR_DATA // 9 elements, 0x58 bytes (sizeof)
{
/*0x000*/ ULONG32 Length;
/*0x004*/ UINT8 Initialized;
/*0x005*/ UINT8 _PADDING0_[0x3];
/*0x008*/ VOID* SsHandle;
/*0x010*/ struct _LIST_ENTRY InLoadOrderModuleList; // 2 elements, 0x10 bytes (sizeof)
/*0x020*/ struct _LIST_ENTRY InMemoryOrderModuleList; // 2 elements, 0x10 bytes (sizeof)
/*0x030*/ struct _LIST_ENTRY InInitializationOrderModuleList; // 2 elements, 0x10 bytes (sizeof)
/*0x040*/ VOID* EntryInProgress;
/*0x048*/ UINT8 ShutdownInProgress;
/*0x049*/ UINT8 _PADDING1_[0x7];
/*0x050*/ VOID* ShutdownThreadId;
}PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef struct _PEB64
{
UCHAR InheritedAddressSpace;
UCHAR ReadImageFileExecOptions;
UCHAR BeingDebugged;
UCHAR BitField;
ULONG64 Mutant;
ULONG64 ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
ULONG64 SubSystemData;
ULONG64 ProcessHeap;
ULONG64 FastPebLock;
ULONG64 AtlThunkSListPtr;
ULONG64 IFEOKey;
ULONG64 CrossProcessFlags;
ULONG64 UserSharedInfoPtr;
ULONG SystemReserved;
ULONG AtlThunkSListPtr32;
ULONG64 ApiSetMap;
} PEB64, *PPEB64;
#pragma pack(4)
typedef struct _PEB32
{
UCHAR InheritedAddressSpace;
UCHAR ReadImageFileExecOptions;
UCHAR BeingDebugged;
UCHAR BitField;
ULONG Mutant;
ULONG ImageBaseAddress;
ULONG Ldr;
ULONG ProcessParameters;
ULONG SubSystemData;
ULONG ProcessHeap;
ULONG FastPebLock;
ULONG AtlThunkSListPtr;
ULONG IFEOKey;
ULONG CrossProcessFlags;
ULONG UserSharedInfoPtr;
ULONG SystemReserved;
ULONG AtlThunkSListPtr32;
ULONG ApiSetMap;
} PEB32, *PPEB32;
typedef struct _PEB_LDR_DATA32
{
ULONG Length;
BOOLEAN Initialized;
ULONG SsHandle;
LIST_ENTRY32 InLoadOrderModuleList;
LIST_ENTRY32 InMemoryOrderModuleList;
LIST_ENTRY32 InInitializationOrderModuleList;
ULONG EntryInProgress;
} PEB_LDR_DATA32, *PPEB_LDR_DATA32;
typedef struct _LDR_DATA_TABLE_ENTRY32
{
LIST_ENTRY32 InLoadOrderLinks;
LIST_ENTRY32 InMemoryOrderModuleList;
LIST_ENTRY32 InInitializationOrderModuleList;
ULONG DllBase;
ULONG EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING32 FullDllName;
UNICODE_STRING32 BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union
{
LIST_ENTRY32 HashLinks;
ULONG SectionPointer;
}u1;
ULONG CheckSum;
union
{
ULONG TimeDateStamp;
ULONG LoadedImports;
}u2;
ULONG EntryPointActivationContext;
ULONG PatchInformation;
} LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;
#pragma pack()
接着就来实现对PEB的获取操作,以64位为例,我们需要调用PsGetProcessPeb()这个内核函数,因为该内核函数没有被公开所以调用之前需要头部导出,该函数需要传入用户进程的EProcess结构,该结构可用PsLookupProcessByProcessId函数动态获取到,获取到以后直接KeStackAttachProcess()附加到应用层进程上,即可直接输出进程的PEB结构信息,如下代码。
#include "peb.h"
#include <ntifs.h>
// 定义导出
NTKERNELAPI PVOID NTAPI PsGetProcessPeb(_In_ PEPROCESS Process);
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint(("Uninstall Driver Is OK \n"));
}
// LyShark
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark \n");
NTSTATUS status = STATUS_UNSUCCESSFUL;
PEPROCESS eproc = NULL;
KAPC_STATE kpc = { 0 };
PPEB64 pPeb64 = NULL;
__try
{
// HANDLE)4656 进程PID
status = PsLookupProcessByProcessId((HANDLE)4656, &eproc);
// 得到64位PEB
pPeb64 = (PPEB64)PsGetProcessPeb(eproc);
DbgPrint("PEB64 = %p \n", pPeb64);
if (pPeb64 != 0)
{
// 验证可读性
ProbeForRead(pPeb64, sizeof(PEB32), 1);
// 附加进程
KeStackAttachProcess(eproc, &kpc);
DbgPrint("进程基地址: 0x%p \n", pPeb64->ImageBaseAddress);
DbgPrint("ProcessHeap = 0x%p \n", pPeb64->ProcessHeap);
DbgPrint("BeingDebugged = %d \n", pPeb64->BeingDebugged);
// 脱离进程
KeUnstackDetachProcess(&kpc);
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
PEB64代码运行后,我们加载驱动即可看到如下结果:

而相对于64位进程来说,获取32位进程的PEB信息可以直接调用PsGetProcessWow64Process()函数得到,该函数已被导出可以任意使用,获取PEB代码如下。
#include "peb.h"
#include <ntifs.h>
// 定义导出
NTKERNELAPI PVOID NTAPI PsGetProcessPeb(_In_ PEPROCESS Process);
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint(("Uninstall Driver Is OK \n"));
}
// LyShark
NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
DbgPrint("hello lyshark \n");
NTSTATUS status = STATUS_UNSUCCESSFUL;
PEPROCESS eproc = NULL;
KAPC_STATE kpc = { 0 };
PPEB32 pPeb32 = NULL;
__try
{
// HANDLE)4656 进程PID
status = PsLookupProcessByProcessId((HANDLE)6164, &eproc);
// 得到32位PEB
pPeb32 = (PPEB32)PsGetProcessWow64Process(eproc);
DbgPrint("PEB32 = %p \n", pPeb32);
if (pPeb32 != 0)
{
// 验证可读性
ProbeForRead(pPeb32, sizeof(PEB32), 1);
// 附加进程
KeStackAttachProcess(eproc, &kpc);
DbgPrint("进程基地址: 0x%p \n", pPeb32->ImageBaseAddress);
DbgPrint("ProcessHeap = 0x%p \n", pPeb32->ProcessHeap);
DbgPrint("BeingDebugged = %d \n", pPeb32->BeingDebugged);
// 脱离进程
KeUnstackDetachProcess(&kpc);
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
Driver->DriverUnload = UnDriver;
return STATUS_SUCCESS;
}
PEB32代码运行后,我们加载驱动即可看到如下结果:

尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)