我这个项目是用VS2015 Community创建的。项目里设置的编译目标平台是Win8.1,底层库设置的VS2015,估计低版本的VS打开项目里的C++项目应该会有问题,而且因为我系统是Win7(还没装Win7 SDK)(拿到电脑就是Win7 sp1了,懒得处理了),在调试和编译时有很多麻烦,VS2015在编译C++时还会添加很多私货,在注册COM组件时还需要dcomp.dll、IEShims.dll、ucrtbased.dll(Win10 SDK)这3个dll。

dcomp.dll(网上下的)

C:\Program Files (x86)\Internet Explorer\IEShims.dll

C:\Program Files (x86)\Windows Kits\10\bin\x86\ucrt\ucrtbased.dll

C:\Program Files (x86)\Windows Kits\10\bin\x64\ucrt\ucrtbased.dll

1

2

3

4

dcomp.dll(网上下的)

C:\ProgramFiles(x86)\InternetExplorer\IEShims.dll

C:\ProgramFiles(x86)\WindowsKits\10\bin\x86\ucrt\ucrtbased.dll

C:\ProgramFiles(x86)\WindowsKits\10\bin\x64\ucrt\ucrtbased.dll

然而加了这几个dll,我写的那2个COM组件还是跑不起来(软爹WCNM

Nektra.Deviare2还是挺好用的。源代码编译后,使用regsvr32注册DeviareCOM.dll和DeviareCOM64.dll两个COM组件。

然后把生成的Nektra.Deviare2.dll添加引用到需要使用Deviare2的项目。DvAgent.dll是给C++用的。deviare32.db和deviare64.db是数据库文件,似乎并用不到(或者说已经在用了,直接用了COM组件注册的地方读入了???以后再研究吧)。

Deviare2启动时内建了任务管理器,可以通过进程名称获得需要hook的那个进程。 然后注册API调用事件OnWriteFileCalled,添加WriteFile Hook,Hook模式为eNktHookFlags.flgOnlyPostCall & eNktHookFlags.flgRestrictAutoHookToSameExecutable,前面的意思是每次传给Windows前触发,后面的意思同进程内循环自动触发?

C#

public WriteFileHooker(string proccessName)

{

_spyMgr = new NktSpyMgr();

_spyMgr.Initialize();

_spyMgr.OnFunctionCalled += new DNktSpyMgrEvents_OnFunctionCalledEventHandler(OnWriteFileCalled);

GetProcess(proccessName);

if (_process == null)

{

//TODO: 没有监听进程时怎么办

//Environment.Exit(0);

throw new Exception("没找到进程" + proccessName);

}

NktHook hook = _spyMgr.CreateHook("Kernel32.dll!WriteFile", (int)(eNktHookFlags.flgOnlyPostCall & eNktHookFlags.flgRestrictAutoHookToSameExecutable));

hook.Hook(true);

hook.Attach(_process, true);

processHandle = WinApi.OpenProcess(WinEnum.PROCESS_WM_READ | WinEnum.PROCESS_DUP_HANDLE, false, _process.Id);

}

private bool GetProcess(string proccessName)

{

NktProcessesEnum enumProcess = _spyMgr.Processes();

NktProcess tempProcess = enumProcess.First();

while (tempProcess != null)

{

//Console.Out.WriteLine(tempProcess.Name);

if (tempProcess.Name.Contains(proccessName) && tempProcess.PlatformBits > 0 && tempProcess.PlatformBits <= IntPtr.Size * 8)

{

_process = tempProcess;

return true;

}

tempProcess = enumProcess.Next();

}

_process = null;

return false;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

publicWriteFileHooker(stringproccessName)

{

_spyMgr=newNktSpyMgr();

_spyMgr.Initialize();

_spyMgr.OnFunctionCalled+=newDNktSpyMgrEvents_OnFunctionCalledEventHandler(OnWriteFileCalled);

GetProcess(proccessName);

if(_process==null)

{

//TODO: 没有监听进程时怎么办

//Environment.Exit(0);

thrownewException("没找到进程"+proccessName);

}

NktHookhook=_spyMgr.CreateHook("Kernel32.dll!WriteFile",(int)(eNktHookFlags.flgOnlyPostCall&eNktHookFlags.flgRestrictAutoHookToSameExecutable));

hook.Hook(true);

hook.Attach(_process,true);

processHandle=WinApi.OpenProcess(WinEnum.PROCESS_WM_READ|WinEnum.PROCESS_DUP_HANDLE,false,_process.Id);

}

privateboolGetProcess(stringproccessName)

{

NktProcessesEnumenumProcess=_spyMgr.Processes();

NktProcesstempProcess=enumProcess.First();

while(tempProcess!=null)

{

//Console.Out.WriteLine(tempProcess.Name);

if(tempProcess.Name.Contains(proccessName)&&tempProcess.PlatformBits>0&&tempProcess.PlatformBits<=IntPtr.Size*8)

{

_process=tempProcess;

returntrue;

}

tempProcess=enumProcess.Next();

}

_process=null;

returnfalse;

}

API调用事件处理函数接受3个参数,参数3 hookCallInfo是API调用时的参数。我们只要处理参数3里的数据。参考WInApi的结构,WriteFile函数有5个参数,分别是文件句柄、写入缓冲区、写入字节数、实际写入字节数、不知道干啥用的某结构体指针(这里用不到)。通过hookCallInfo.Params().Next() 依次获取各个参数。

C#

//

//BOOL WINAPI WriteFile(

// _In_ HANDLE hFile,

// _In_ LPCVOID lpBuffer,

// _In_ DWORD nNumberOfBytesToWrite,

// _Out_opt_ LPDWORD lpNumberOfBytesWritten,

// _Inout_opt_ LPOVERLAPPED lpOverlapped

//);

//

///

/// WriteFile调用事件处理函数

///

///

///

///

private void OnWriteFileCalled(NktHook hook, NktProcess process, NktHookCallInfo hookCallInfo)

{

string strDocument = "Document: ";

INktParamsEnum paramsEnum = hookCallInfo.Params();

INktParam hFile = paramsEnum.First();

INktParam lpBuffer = paramsEnum.Next();

INktParam nNumberOfBytesToWrite = paramsEnum.Next();

#region 看着官方示例写的 毛用没有

if (hFile.PointerVal != IntPtr.Zero)

{

INktParamsEnum hFileEnumStruct = hFile.Evaluate().Fields();

INktParam hFileStruct = hFileEnumStruct.First();

}

Console.Out.WriteLine(lpBuffer.ReadString());

#endregion

var h_file = QueryFileHandle(hFile.Address);

ReadBuffer(lpBuffer.Address, nNumberOfBytesToWrite.Address);

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

//

//BOOL WINAPI WriteFile(

//  _In_ HANDLE       hFile,

//  _In_ LPCVOID      lpBuffer,

//  _In_ DWORD        nNumberOfBytesToWrite,

//  _Out_opt_ LPDWORD      lpNumberOfBytesWritten,

//  _Inout_opt_ LPOVERLAPPED lpOverlapped

//);

//

///

/// WriteFile调用事件处理函数

///

///

///

///

privatevoidOnWriteFileCalled(NktHookhook,NktProcessprocess,NktHookCallInfohookCallInfo)

{

stringstrDocument="Document: ";

INktParamsEnumparamsEnum=hookCallInfo.Params();

INktParamhFile=paramsEnum.First();

INktParamlpBuffer=paramsEnum.Next();

INktParamnNumberOfBytesToWrite=paramsEnum.Next();

#region 看着官方示例写的 毛用没有

if(hFile.PointerVal!=IntPtr.Zero)

{

INktParamsEnumhFileEnumStruct=hFile.Evaluate().Fields();

INktParamhFileStruct=hFileEnumStruct.First();

}

Console.Out.WriteLine(lpBuffer.ReadString());

#endregion

varh_file=QueryFileHandle(hFile.Address);

ReadBuffer(lpBuffer.Address,nNumberOfBytesToWrite.Address);

}

官方示例(一个打印机hook程序)里用了lpBuffer.ReadString()就能直接获得缓冲区内文本内容,然而这里不行,这里的lpBuffer 是一个指针。这时就需要另外神奇的操作的了。

我们在注册目标进程时还运行了

C#

WinApi.OpenProcess(WinEnum.PROCESS_WM_READ | WinEnum.PROCESS_DUP_HANDLE, false, _process.Id);

1

WinApi.OpenProcess(WinEnum.PROCESS_WM_READ|WinEnum.PROCESS_DUP_HANDLE,false,_process.Id);

OpenProcess这个WinApi赋予了我们当前进程读取目标进程内存和复制句柄的权限。获得授权之后我们就可以调用别的WinApi任意调♂戏目标进程了。

关于目标进程到底调用WriteFile写了些什么可以通过直接把内存读爆的方式就知道了。

C#

///

/// 内存读爆

///

///

///

private void ReadBuffer(IntPtr p_buffer, IntPtr p_size)

{

byte[] _size = new byte[4];

int readedbtyes = 0;

var result = WinApi.ReadProcessMemory(processHandle.ToInt32(), p_size.ToInt32(), _size, 4, ref readedbtyes);

int size = WinApi.ToInt32(_size);

byte[] _bufferpoint = new byte[PtrSize];

result = WinApi.ReadProcessMemory(processHandle.ToInt32(), p_buffer.ToInt32(), _bufferpoint, PtrSize, ref readedbtyes);

int bufferpoint = WinApi.ToInt32(_bufferpoint);

byte[] _buffer = new byte[size];

result = WinApi.ReadProcessMemory(processHandle.ToInt32(), bufferpoint, _buffer, size, ref readedbtyes);

Console.Out.WriteLine(Encoding.Default.GetString(_buffer));

Console.Out.WriteLine(Encoding.UTF8.GetString(_buffer));

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

///

/// 内存读爆

///

///

///

privatevoidReadBuffer(IntPtrp_buffer,IntPtrp_size)

{

byte[]_size=newbyte[4];

intreadedbtyes=0;

varresult=WinApi.ReadProcessMemory(processHandle.ToInt32(),p_size.ToInt32(),_size,4,refreadedbtyes);

intsize=WinApi.ToInt32(_size);

byte[]_bufferpoint=newbyte[PtrSize];

result=WinApi.ReadProcessMemory(processHandle.ToInt32(),p_buffer.ToInt32(),_bufferpoint,PtrSize,refreadedbtyes);

intbufferpoint=WinApi.ToInt32(_bufferpoint);

byte[]_buffer=newbyte[size];

result=WinApi.ReadProcessMemory(processHandle.ToInt32(),bufferpoint,_buffer,size,refreadedbtyes);

Console.Out.WriteLine(Encoding.Default.GetString(_buffer));

Console.Out.WriteLine(Encoding.UTF8.GetString(_buffer));

}

然而问题是现在还不知道目标进程写了哪个文件。因为把堆栈上的hFile指针的内存数据读出来的结果是7,7是啥意思根本不知道。还好还可以用WinDbg调试目标进程,使用

!handle

1

!handle

可以列出进程中所有的句柄。通过数数发现这个7的意思是进程中第7个文件句柄 。当然因为这是隔壁进程的句柄,直接通过GetFullPathName这个WinApi是没法获得文件路径的。这种时候又有软爹隐藏黑科技,用SYSTEMHANDLEINFORMATION(16)参数调用ZwQuerySystemInformation函数可以获得系统中所有的句柄信息。

然而系统中句柄太多,用.net的Pinvoke的方式去调用直接就炸了(见上篇)。我写了两个COM组件,然而却都用不了(应该是vs编译的原因)。只能用C++/CLI的方式在非托管的状态下用C++调用WinApi然后通过过滤进程pid来减少句柄数,最后直接封装成托管对象返回给.net。其中FileObject的ObjectType是28(妈的,一个个试出来的)。C++/CLI的语法真tmd绕,用的时候头都大了。

C#

// WinApiReader.h

#pragma once

using namespace System;

namespace WinApiReader {

public ref class SystemHandle

{

public:

//这里用了C++类型,在C++环境下使用会比较简单,到托管环境下会自动转换成托管类型

unsigned int ProcessId;

unsigned char ObjectType;

unsigned char Flags;

unsigned short Value;

unsigned int Address;

unsigned int GrantedAccess;

};

public ref class SystemHandleInfo

{

public:

int Count;

//没想到吧,数组是这么声明的

array ^SystemHandles;

};

public ref class WinApiReader

{

public:

//没想到吧,还有[System::Runtime::InteropServices::OutAttribute]这种操作,这个可以实现C#中out关键字

int QueryProcessHandleInfo(int ProcessId, [System::Runtime::InteropServices::OutAttribute] SystemHandleInfo^% HandleInfo);

};

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

// WinApiReader.h

#pragma once

usingnamespaceSystem;

namespaceWinApiReader{

publicrefclassSystemHandle

{

public:

//这里用了C++类型,在C++环境下使用会比较简单,到托管环境下会自动转换成托管类型

unsignedintProcessId;

unsignedcharObjectType;

unsignedcharFlags;

unsignedshortValue;

unsignedintAddress;

unsignedintGrantedAccess;

};

publicrefclassSystemHandleInfo

{

public:

intCount;

//没想到吧,数组是这么声明的

array^SystemHandles;

};

publicrefclassWinApiReader

{

public:

//没想到吧,还有[System::Runtime::InteropServices::OutAttribute]这种操作,这个可以实现C#中out关键字

intQueryProcessHandleInfo(intProcessId,[System::Runtime::InteropServices::OutAttribute]SystemHandleInfo^%HandleInfo);

};

}

C++

// 这是主 DLL 文件。

#include "stdafx.h"

#include

#include "WinApiReader.h"

//int QueryProcessHandleInfo(int process)

//WinApi用的结构体,句柄信息

typedef struct _SYSTEM_HANDLE

{

DWORD dwProcessId;

BYTE bObjectType;

BYTE bFlags;

WORD wValue;

PVOID pAddress;

DWORD GrantedAccess;

}

SYSTEM_HANDLE;

//WinApi用的结构体,句柄信息数组

typedef struct _SYSTEM_HANDLE_INFORMATION

{

ULONG Count;

SYSTEM_HANDLE SystemHandles[];

}

SYSTEM_HANDLE_INFORMATION;

//NTSTAUS 长度不匹配,这里引用ntstaus.h会编译过不了(太迷了)

#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004L

//ZwQuerySystemInformation函数指针

typedef unsigned long(*ZWQUERYSYSTEMINFORMATION)(int SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);

//获取目标进程的所有句柄

int WinApiReader::WinApiReader::QueryProcessHandleInfo(int ProcessId, [System::Runtime::InteropServices::OutAttribute] SystemHandleInfo^% HandleInfo)

{

HMODULE hNtDLL = LoadLibrary(L"NTDLL.DLL");

if (!hNtDLL)

{

return FALSE;

}

ZWQUERYSYSTEMINFORMATION ZwQuerySystemInformation = (ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtDLL, "ZwQuerySystemInformation");

if (ZwQuerySystemInformation == NULL)

{

return FALSE;

}

ULONG mSize = 0x8000;

PVOID mPtr;

ULONG status;

//进程的堆内存

HANDLE hHeap = GetProcessHeap();

//这里用了一个循环来开辟一个堆内存空间用来存放函数调用结果(因为太♂大了)

do

{

mPtr = HeapAlloc(hHeap, 0, mSize);

if (!mPtr) return NULL;

memset(mPtr, 0, mSize);

status = ZwQuerySystemInformation(16, mPtr, mSize, NULL);

if (status == STATUS_INFO_LENGTH_MISMATCH)

{

HeapFree(hHeap, 0, mPtr);

mSize = mSize * 2;

}

} while (status == STATUS_INFO_LENGTH_MISMATCH);

int allCount = ((SYSTEM_HANDLE_INFORMATION*)mPtr)->Count;

int outArrLen = allCount / 10;

PVOID pOutArr;

int outArrSize = sizeof(SYSTEM_HANDLE) * outArrLen;

pOutArr = HeapAlloc(hHeap, 0, outArrSize);

memset(pOutArr, 0, outArrSize);

SYSTEM_HANDLE* outArr = (SYSTEM_HANDLE*)pOutArr;

//筛选出目标进程的所有句柄

int outCount = 0;

SYSTEM_HANDLE item;

for (int i = 0; i < allCount; i++)

{

item = ((SYSTEM_HANDLE_INFORMATION*)mPtr)->SystemHandles[i];

if (item.dwProcessId == ProcessId)

{

outArr[outCount].bFlags = item.bFlags;

outArr[outCount].bObjectType = item.bObjectType;

outArr[outCount].dwProcessId = item.dwProcessId;

outArr[outCount].GrantedAccess = item.GrantedAccess;

outArr[outCount].pAddress = item.pAddress;

outArr[outCount].wValue = item.wValue;

outCount++;

}

}

/*PVOID pOutHandleInfo;

int outTrueArr = sizeof(SYSTEM_HANDLE) * (outCount - 1);

int outHandleInfoSize = sizeof(SYSTEM_HANDLE_INFORMATION) + outTrueArr;

pOutHandleInfo = HeapAlloc(hHeap, 0, outHandleInfoSize);

memset(pOutHandleInfo, 0, outHandleInfoSize);

SYSTEM_HANDLE_INFORMATION* outHandleInfo = (SYSTEM_HANDLE_INFORMATION*)pOutHandleInfo;

outHandleInfo->Count = outCount - 1;

memcpy(outHandleInfo->SystemHandles, outArr, outTrueArr);

ProcessHandleInfo = (ULONG*)pOutHandleInfo;*/

//手工装箱

HandleInfo = gcnew SystemHandleInfo();

HandleInfo->Count = outCount;

HandleInfo->SystemHandles = gcnew array(outCount);

for (int i = 0; i < outCount; i++)

{

HandleInfo->SystemHandles[i] = gcnew SystemHandle();

HandleInfo->SystemHandles[i]->ProcessId = outArr[i].dwProcessId;

HandleInfo->SystemHandles[i]->Address = (unsigned int)outArr[i].pAddress;

HandleInfo->SystemHandles[i]->Flags = outArr[i].bFlags;

HandleInfo->SystemHandles[i]->ObjectType = outArr[i].bObjectType;

HandleInfo->SystemHandles[i]->GrantedAccess = outArr[i].GrantedAccess;

HandleInfo->SystemHandles[i]->Value = outArr[i].wValue;

}

//释放堆内存

HeapFree(hHeap, 0, mPtr);

HeapFree(hHeap, 0, pOutArr);

return 1;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

// 这是主 DLL 文件。

#include "stdafx.h"

#include

#include "WinApiReader.h"

//int QueryProcessHandleInfo(int process)

//WinApi用的结构体,句柄信息

typedefstruct_SYSTEM_HANDLE

{

DWORDdwProcessId;

BYTEbObjectType;

BYTEbFlags;

WORDwValue;

PVOIDpAddress;

DWORDGrantedAccess;

}

SYSTEM_HANDLE;

//WinApi用的结构体,句柄信息数组

typedefstruct_SYSTEM_HANDLE_INFORMATION

{

ULONGCount;

SYSTEM_HANDLESystemHandles[];

}

SYSTEM_HANDLE_INFORMATION;

//NTSTAUS 长度不匹配,这里引用ntstaus.h会编译过不了(太迷了)

#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004L

//ZwQuerySystemInformation函数指针

typedefunsignedlong(*ZWQUERYSYSTEMINFORMATION)(intSystemInformationClass,PVOIDSystemInformation,ULONGSystemInformationLength,PULONGReturnLength);

//获取目标进程的所有句柄

intWinApiReader::WinApiReader::QueryProcessHandleInfo(intProcessId,[System::Runtime::InteropServices::OutAttribute]SystemHandleInfo^%HandleInfo)

{

HMODULEhNtDLL=LoadLibrary(L"NTDLL.DLL");

if(!hNtDLL)

{

returnFALSE;

}

ZWQUERYSYSTEMINFORMATIONZwQuerySystemInformation=(ZWQUERYSYSTEMINFORMATION)GetProcAddress(hNtDLL,"ZwQuerySystemInformation");

if(ZwQuerySystemInformation==NULL)

{

returnFALSE;

}

ULONGmSize=0x8000;

PVOIDmPtr;

ULONGstatus;

//进程的堆内存

HANDLEhHeap=GetProcessHeap();

//这里用了一个循环来开辟一个堆内存空间用来存放函数调用结果(因为太♂大了)

do

{

mPtr=HeapAlloc(hHeap,0,mSize);

if(!mPtr)returnNULL;

memset(mPtr,0,mSize);

status=ZwQuerySystemInformation(16,mPtr,mSize,NULL);

if(status==STATUS_INFO_LENGTH_MISMATCH)

{

HeapFree(hHeap,0,mPtr);

mSize=mSize*2;

}

}while(status==STATUS_INFO_LENGTH_MISMATCH);

intallCount=((SYSTEM_HANDLE_INFORMATION*)mPtr)->Count;

intoutArrLen=allCount/10;

PVOIDpOutArr;

intoutArrSize=sizeof(SYSTEM_HANDLE)*outArrLen;

pOutArr=HeapAlloc(hHeap,0,outArrSize);

memset(pOutArr,0,outArrSize);

SYSTEM_HANDLE*outArr=(SYSTEM_HANDLE*)pOutArr;

//筛选出目标进程的所有句柄

intoutCount=0;

SYSTEM_HANDLEitem;

for(inti=0;i

{

item=((SYSTEM_HANDLE_INFORMATION*)mPtr)->SystemHandles[i];

if(item.dwProcessId==ProcessId)

{

outArr[outCount].bFlags=item.bFlags;

outArr[outCount].bObjectType=item.bObjectType;

outArr[outCount].dwProcessId=item.dwProcessId;

outArr[outCount].GrantedAccess=item.GrantedAccess;

outArr[outCount].pAddress=item.pAddress;

outArr[outCount].wValue=item.wValue;

outCount++;

}

}

/*PVOID pOutHandleInfo;

int outTrueArr = sizeof(SYSTEM_HANDLE) * (outCount - 1);

int outHandleInfoSize = sizeof(SYSTEM_HANDLE_INFORMATION) + outTrueArr;

pOutHandleInfo = HeapAlloc(hHeap, 0, outHandleInfoSize);

memset(pOutHandleInfo, 0, outHandleInfoSize);

SYSTEM_HANDLE_INFORMATION* outHandleInfo = (SYSTEM_HANDLE_INFORMATION*)pOutHandleInfo;

outHandleInfo->Count = outCount - 1;

memcpy(outHandleInfo->SystemHandles, outArr, outTrueArr);

ProcessHandleInfo = (ULONG*)pOutHandleInfo;*/

//手工装箱

HandleInfo=gcnewSystemHandleInfo();

HandleInfo->Count=outCount;

HandleInfo->SystemHandles=gcnewarray(outCount);

for(inti=0;i

{

HandleInfo->SystemHandles[i]=gcnewSystemHandle();

HandleInfo->SystemHandles[i]->ProcessId=outArr[i].dwProcessId;

HandleInfo->SystemHandles[i]->Address=(unsignedint)outArr[i].pAddress;

HandleInfo->SystemHandles[i]->Flags=outArr[i].bFlags;

HandleInfo->SystemHandles[i]->ObjectType=outArr[i].bObjectType;

HandleInfo->SystemHandles[i]->GrantedAccess=outArr[i].GrantedAccess;

HandleInfo->SystemHandles[i]->Value=outArr[i].wValue;

}

//释放堆内存

HeapFree(hHeap,0,mPtr);

HeapFree(hHeap,0,pOutArr);

return1;

}

C++/CLI生成的dll并不是COM组件,可以直接引用到项目中,using之后就可以直接调用了。拿到真实的hFile的handle地址后就可以用DuplicateHandle函数复制一个句柄到自己的进程空间中,之后可以用File系WinApi随意调♂戏了。

C#

WinApi.DuplicateHandle(processHandle.ToInt32(), p_hfile.ToInt32(), hCurProcess, ref my_hfile, 0x80000000, false, 2);

1

WinApi.DuplicateHandle(processHandle.ToInt32(),p_hfile.ToInt32(),hCurProcess,refmy_hfile,0x80000000,false,2);

C#

///

/// 把远程file handle复制到本地进程

/// 然后获取文件名

///

///

private unsafe void ReadFileInfo(IntPtr p_hfile)

{

IntPtr my_hfile = new IntPtr(-1);

int hCurProcess = -1;//WinApi.GetCurrentProcess();

bool result;

result = WinApi.DuplicateHandle(processHandle.ToInt32(), p_hfile.ToInt32(), hCurProcess, ref my_hfile, 0x80000000, false, 2);

#region GetFileInformationByHandle 文件最基本信息 竟然没文件名

var fileinfo = new BY_HANDLE_FILE_INFORMATION();

result = WinApi.GetFileInformationByHandle(my_hfile.ToInt32(), ref fileinfo);

#endregion

#region GetFileInformationByHandleEx

var fileinfo2 = new FILE_FULL_DIR_INFO();

int fileInfo2Type = (int)FileInformationClass.FileFullDirectoryInfo;//0xe;

//本来想用开辟非托管内存的操作,传指针到winapi,后来发现那块内存有数据后用

//PtrToStructure转结构体报错,也许是操作问题,还不如直接传结构体

int size2 = Marshal.SizeOf(fileinfo2);

IntPtr p_fileInfo2 = Marshal.AllocHGlobal(size2);

Marshal.StructureToPtr(fileinfo2, p_fileInfo2, false);

//调用失败 大概是LARGE_INTEGER 这个union的结构不对

result = WinApi.GetFileInformationByHandleEx(my_hfile.ToInt32(), fileInfo2Type, ref fileinfo2, size2);

var fileinfo3 = new FILE_NAME_INFO();

int fileInfo3Type = (int)FileInformationClass.FileNameInfo;//0x2;

int size3 = Marshal.SizeOf(fileinfo3) + 1000*2;

IntPtr p_fileInfo3 = Marshal.AllocHGlobal(size3);

Marshal.StructureToPtr(fileinfo3, p_fileInfo3, false);

//\otherproject\WriteFileHook\Log4netLoger\bin\x86\Debug\Logs\debug.log20170901

result = WinApi.GetFileInformationByHandleEx(my_hfile.ToInt32(), fileInfo3Type, ref fileinfo3, size3);

StringBuilder fn3 = new StringBuilder(1000);

int len3 = WinApi.GetFullPathName(fileinfo3.FileName, 1000, fn3, null);

//输出正常路径

//E:\otherproject\WriteFileHook\Log4netLoger\bin\x86\Debug\Logs\debug.log20170901

Console.Out.WriteLine(fn3);

#endregion

#region GetFinalPathNameByHandle

StringBuilder fileName = new StringBuilder(1000);

//获取的带设备路径

//\Device\HarddiskVolume4\otherproject\WriteFileHook\Log4netLoger\bin\x86\Debug\Logs\debug.log20170901

int size4 = WinApi.GetFinalPathNameByHandle(my_hfile.ToInt32(), fileName, 1000, 0x2);

StringBuilder fn4 = new StringBuilder(1000);

//会在前面在加个盘符,然而没去掉设备路径,超谐

//有专门根据设备路径获取盘符路径的方法

//E:\Device\HarddiskVolume4\otherproject\WriteFileHook\Log4netLoger\bin\x86\Debug\Logs\debug.log20170901

int len4 = WinApi.GetFullPathName(fileName.ToString(), 1000, fn4, null);

Console.Out.WriteLine(fn4);

#endregion

#region ZwQueryInformationFile

//GetFileInformationByHandleEx 内部调用的就是这个吧(

var fileStatus5 = new IO_STATUS_BLOCK();

int ssize5 = Marshal.SizeOf(fileStatus5);

IntPtr p_fileStatus5 = Marshal.AllocHGlobal(ssize5);

Marshal.StructureToPtr(fileStatus5, p_fileStatus5, false);

var fileinfo5 = new FILE_NAME_INFO();

int fileInfo5Type = (int)FileInformationClass.FileFullDirectoryInfo;//9;

int size5 = Marshal.SizeOf(fileinfo5) + 1000*2;

IntPtr p_fileInfo5 = Marshal.AllocHGlobal(size5);

Marshal.StructureToPtr(fileinfo5, p_fileInfo5, false);

int ret = WinApi.ZwQueryInformationFile(my_hfile.ToInt32(), ref fileStatus5, ref fileinfo5, size5, fileInfo5Type);

//\otherproject\WriteFileHook\Log4netLoger\bin\x86\Debug\Logs\debug.log20170901

Console.Out.WriteLine(fileinfo5.FileName);

#endregion

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

///

/// 把远程file handle复制到本地进程

/// 然后获取文件名

///

///

privateunsafevoidReadFileInfo(IntPtrp_hfile)

{

IntPtrmy_hfile=newIntPtr(-1);

inthCurProcess=-1;//WinApi.GetCurrentProcess();

boolresult;

result=WinApi.DuplicateHandle(processHandle.ToInt32(),p_hfile.ToInt32(),hCurProcess,refmy_hfile,0x80000000,false,2);

#region GetFileInformationByHandle 文件最基本信息 竟然没文件名

varfileinfo=newBY_HANDLE_FILE_INFORMATION();

result=WinApi.GetFileInformationByHandle(my_hfile.ToInt32(),reffileinfo);

#endregion

#region GetFileInformationByHandleEx

varfileinfo2=newFILE_FULL_DIR_INFO();

intfileInfo2Type=(int)FileInformationClass.FileFullDirectoryInfo;//0xe;

//本来想用开辟非托管内存的操作,传指针到winapi,后来发现那块内存有数据后用

//PtrToStructure转结构体报错,也许是操作问题,还不如直接传结构体

intsize2=Marshal.SizeOf(fileinfo2);

IntPtrp_fileInfo2=Marshal.AllocHGlobal(size2);

Marshal.StructureToPtr(fileinfo2,p_fileInfo2,false);

//调用失败 大概是LARGE_INTEGER 这个union的结构不对

result=WinApi.GetFileInformationByHandleEx(my_hfile.ToInt32(),fileInfo2Type,reffileinfo2,size2);

varfileinfo3=newFILE_NAME_INFO();

intfileInfo3Type=(int)FileInformationClass.FileNameInfo;//0x2;

intsize3=Marshal.SizeOf(fileinfo3)+1000*2;

IntPtrp_fileInfo3=Marshal.AllocHGlobal(size3);

Marshal.StructureToPtr(fileinfo3,p_fileInfo3,false);

//\otherproject\WriteFileHook\Log4netLoger\bin\x86\Debug\Logs\debug.log20170901

result=WinApi.GetFileInformationByHandleEx(my_hfile.ToInt32(),fileInfo3Type,reffileinfo3,size3);

StringBuilderfn3=newStringBuilder(1000);

intlen3=WinApi.GetFullPathName(fileinfo3.FileName,1000,fn3,null);

//输出正常路径

//E:\otherproject\WriteFileHook\Log4netLoger\bin\x86\Debug\Logs\debug.log20170901

Console.Out.WriteLine(fn3);

#endregion

#region GetFinalPathNameByHandle

StringBuilderfileName=newStringBuilder(1000);

//获取的带设备路径

//\Device\HarddiskVolume4\otherproject\WriteFileHook\Log4netLoger\bin\x86\Debug\Logs\debug.log20170901

intsize4=WinApi.GetFinalPathNameByHandle(my_hfile.ToInt32(),fileName,1000,0x2);

StringBuilderfn4=newStringBuilder(1000);

//会在前面在加个盘符,然而没去掉设备路径,超谐

//有专门根据设备路径获取盘符路径的方法

//E:\Device\HarddiskVolume4\otherproject\WriteFileHook\Log4netLoger\bin\x86\Debug\Logs\debug.log20170901

intlen4=WinApi.GetFullPathName(fileName.ToString(),1000,fn4,null);

Console.Out.WriteLine(fn4);

#endregion

#region ZwQueryInformationFile

//GetFileInformationByHandleEx 内部调用的就是这个吧(

varfileStatus5=newIO_STATUS_BLOCK();

intssize5=Marshal.SizeOf(fileStatus5);

IntPtrp_fileStatus5=Marshal.AllocHGlobal(ssize5);

Marshal.StructureToPtr(fileStatus5,p_fileStatus5,false);

varfileinfo5=newFILE_NAME_INFO();

intfileInfo5Type=(int)FileInformationClass.FileFullDirectoryInfo;//9;

intsize5=Marshal.SizeOf(fileinfo5)+1000*2;

IntPtrp_fileInfo5=Marshal.AllocHGlobal(size5);

Marshal.StructureToPtr(fileinfo5,p_fileInfo5,false);

intret=WinApi.ZwQueryInformationFile(my_hfile.ToInt32(),reffileStatus5,reffileinfo5,size5,fileInfo5Type);

//\otherproject\WriteFileHook\Log4netLoger\bin\x86\Debug\Logs\debug.log20170901

Console.Out.WriteLine(fileinfo5.FileName);

#endregion

}

这样就可以通过这么复杂的方式知道隔壁进程在什么时候向什么文件写什么内容。(我为什么要做这种偷窥的事情呢,因为很刺激啊(

后记:软爹wcnm

c++ 结构体地址 转换成ulong_一个WinApi Hook程序(下)相关推荐

  1. c++ 结构体地址 转换成ulong_零基础入门之结构体字节对齐

    一.字节对齐的规则: 1.一般设置的对齐方式为1,2,4字节对齐方式.结构的首地址必须是结构内最宽类型的整数倍地址;另外,结构体的每一个成员起始地址必须是自身类型大小的整数倍(需要特别注意的是wind ...

  2. c++ 结构体地址 转换成ulong_Nicole_coder

    1. 什么是编译 在开始之前,我们必须知道什么是编译?为什么要进行编译? CPU 由上亿个晶体管组成,在运行的时候,单个晶体管只能根据电流的流通或关闭来确认两种状态,我们一般说 0 或 1,根据这种状 ...

  3. 技巧:Go 结构体如何转换成 map[string]interface{}

    本文介绍了Go语言中将结构体转成map[string]interface{}时你需要了解的"坑",也有你需要知道的若干方法. 我们在Go语言中通常使用结构体来保存我们的数据,例如要 ...

  4. 详述在设有快表的请求分页存储管理系统中,一个虚地址转换成物理内存地址的过程。

    详述在设有快表的请求分页存储管理系统中,一个虚地址转换成物理内存地址的过程. first() {//检索快表if(找到){修改页表项访问位if(是写指令){修改位置为"1";}us ...

  5. 详述在设有快表的请求分页存储管理系统中,一个虚地址转换成物理内存地址的过程。...

    详述在设有快表的请求分页存储管理系统中,一个虚地址转换成物理内存地址的过程. first() {//检索快表if(找到){修改页表项访问位if(是写指令){修改位置为"1";}us ...

  6. Android代码(Handler的运用),HttpURLConnection的应用,将url图片地址转换成图片。

     1 布局文件, <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xml ...

  7. ip 十进制 整型 java_IP地址转换成10进制整数(zt)

    一.由域名求IP地址的程序 下面程序由命令行输入域名,输出ip import java.net.*; public class nslookup { //Usage:java nslookup hos ...

  8. 【华为OD机试真题 JS】IPv4地址转换成整数

    标题:IPv4地址转换成整数 | 时间限制:1秒 | 内存限制:262144K | 语言限制:不限 存在一种虚拟IPv4地址,由4小节组成,每节的范围为0~255,以#号间隔,虚拟IPv4地址可以转换 ...

  9. 如何将域名地址转换成对应的IP地址?

    本文摘自:http://blog.163.com/lyzaily@126/blog/static/42438837200910173105834/ 将域名地址转换成IP地址有一个好处,就是我们的服务器 ...

最新文章

  1. R绘制QQ图并解读QQ图
  2. 缺少com.umeng.analytics.MobclickAgent包,引入需注意
  3. PAT1034 Head of a Gang (30)(并查集)
  4. 【Linux系统编程】Linux 线程浅析
  5. python可以帮机器人编程吗_Python如何实现机器人聊天
  6. 中职计算机说课稿三篇,精选中职计算机说课稿三篇-20210609060707.docx-原创力文档...
  7. 论文浅尝 | 混合注意力原型网络的含噪音少样本的关系分类
  8. 2012.4.17总结(一)
  9. mysql监视器MONyog的使用
  10. 还怕Web 安全编程学不会?来这里,准没错!
  11. 济南清北学堂游记 Day 2.
  12. linux环境下安装mencoder转码工具
  13. 关系代数表达式优化步骤
  14. 新广告法违规词、敏感词在线检测工具
  15. Echarts制作标签云图
  16. 开源 java CMS - FreeCMS2.3 移动app站点配置
  17. 图解技术原理,真的太赞了!
  18. 应用ArcGIS和COORD软件进行坐标七参数转换的方法
  19. JS---------------网页版的消灭星星
  20. Linux 静态链接库与动态链接库之一:静态链接库生成及使用

热门文章

  1. Java学习笔记——StringBuilder
  2. 2021年R2移动式压力容器充装证模拟考试题库及R2移动式压力容器充装理论考试试题
  3. creo自定义调用零件库_Creo标准零件库和常用件库的定制和设置
  4. Android跳转至系统位置信息设置界面和wifi设置界面
  5. 活在安达信的日子zz
  6. linux 内核 权限,linux – 内核模块执行中的不同权限
  7. 2022年驾驶员考试网约车驾驶员证考试模拟试题卷及答案
  8. C语言每日一练——第57天:递归解决分鱼问题
  9. java flv 转swf_java实现视频文件转换为flv(带文件缩略图)
  10. mysql计算员工一年工资_一年平均工资怎么算