php
php怎样传参不会被注入?
一、php怎样传参不会被注入?
要防止参数注入,可以采取以下措施:
1. 使用预处理语句:使用PDO或mysqli等数据库扩展,使用预处理语句绑定参数,确保参数值被正确转义和处理,从而防止SQL注入。
2. 输入验证和过滤:对于用户输入的参数,进行严格的验证和过滤,确保只接受预期的数据类型和格式,例如使用filter_var函数进行过滤。
3. 使用参数化查询:在执行数据库查询时,使用参数化查询,将参数作为占位符传递给查询语句,而不是将参数直接拼接到查询语句中,从而避免了注入攻击。
4. 最小化权限:在数据库连接配置中,使用具有最小权限的用户进行连接,限制其对数据库的操作权限,以减少潜在的攻击面。
5. 防止跨站脚本攻击(XSS):对于输出到HTML页面的参数,使用htmlspecialchars函数进行转义,确保用户输入的内容不会被解析为HTML代码。
综上所述,通过使用预处理语句、输入验证和过滤、参数化查询、最小化权限和防止XSS攻击等措施,可以有效防止参数注入。
二、PHP8 注入是单例吗?
PHP8 注入不是单例。在PHP8中,由于引入了FPM进程池,每个请求都会在自己的进程中处理,并且每个进程都会有自己的依赖注入容器。因此,每个请求都会返回一个新的实例,而不是单例。
三、.php文件的开头是php吗?
PHP文件名以php为后缀。PHP代码以“<?php”开头,以“?>”结束,中间为php代码,代码行都必须以分号结束。
四、php framework注入
PHP框架注入:保护您的Web应用程序
PHP框架注入:保护您的Web应用程序
在当今数字化世界中,安全性在开发和维护Web应用程序时至关重要。PHP作为一种流行的服务器端脚本语言,广泛用于构建各种Web应用程序。然而,正因为其广泛使用,PHP应用程序成为黑客攻击的主要目标之一。
什么是PHP框架注入?
PHP框架注入是指黑客通过操纵应用程序的输入,向应用程序中的框架组件注入恶意代码的过程。一旦黑客成功注入恶意代码,他们可以执行各种危险的操作,如数据泄露、数据库破坏和远程执行命令。
框架注入攻击通常发生在未正确验证和过滤用户输入的情况下。PHP框架提供了许多强大的功能和工具,帮助开发人员构建安全的Web应用程序。然而,如果开发人员不正确使用这些功能,应用程序可能会容易受到注入攻击。
如何保护您的PHP框架免受注入攻击?
保护您的PHP框架免受注入攻击是至关重要的。以下是一些重要的步骤和建议:
- 输入验证和过滤:确保您的应用程序对用户输入进行适当的验证和过滤。使用框架提供的过滤器和验证器来验证用户输入,以防止恶意代码注入。
- 参数化查询:使用参数化查询方式执行数据库查询,而不要直接拼接用户输入的值到SQL查询中。这可以防止SQL注入攻击。
- 错误处理:不要向用户显示详细的错误信息,因为这可能暴露应用程序的敏感信息。在生产环境中,将错误信息记录到日志文件中,而不是直接显示给用户。
- 更新框架和依赖项:确保您使用的PHP框架和依赖项的版本是最新的。新版本通常修复了安全漏洞和软件缺陷。
- 安全配置:审查和配置您的PHP框架的安全设置。禁用不必要或潜在危险的功能,启用日志记录和监控功能。
常见的PHP框架注入漏洞
在PHP框架中,有几种常见的注入漏洞。以下是其中一些:
- SQL注入:通过操纵应用程序的SQL查询来执行恶意操作。黑客可以利用未正确过滤和验证的用户输入将额外的SQL代码插入到查询中。
- 命令注入:黑客通过执行未经过滤和验证的用户输入作为操作系统命令的一部分来执行恶意操作。这种类型的注入可能导致黑客完全控制服务器。
- XSS(跨站脚本)注入:黑客通过插入恶意脚本代码来利用应用程序中的漏洞,以在用户的浏览器中执行恶意操作。
- 路径遍历注入:黑客通过在应用程序的文件路径中注入特殊字符,以访问未授权的文件和目录。
PHP框架注入的示例
以下是一个简单的PHP框架注入的示例:
<?php
// 从用户输入获取用户名
$username = $_POST['username'];
// 构建SQL查询
$sql = "SELECT * FROM users WHERE username = '" . $username . "'";
// 执行查询
$result = mysqli_query($connection, $sql);
?>
在上面的示例中,程序获取用户输入的用户名,并将其直接插入到SQL查询中,而没有进行任何验证或过滤。这使得黑客能够通过输入恶意代码来执行SQL注入攻击。
结论
保护您的PHP框架免受注入攻击是至关重要的。通过正确验证和过滤用户输入,使用参数化查询,审查和配置框架的安全设置,您可以大大减少框架注入的风险。
在开发和维护Web应用程序时,安全性应始终是首要任务。使用最新的PHP框架版本,定期进行渗透测试和代码审查,并保持与安全社区的联系以了解最新的威胁和安全建议。
通过采取适当的安全措施,您可以保护您的Web应用程序及其用户免受PHP框架注入等恶意攻击。
五、进程注入的dll文件该怎么编写?
用了半个暑假学C++,hook WX,成功调用发送消息call,接收消息响应call。在B站参考了Hezone和Hellmessage两位大神的视频,虽然WX更新较快,汇编代码已经面目全非,但思路很有启发性。写篇文章记下实现过程,方便日后复习。
用到的工具有:visual studio,cheat engine,ollydbg。
写一个DLL
这个DLL相当于我们的间谍,潜入WX内部,然后和外部主程序通信进行相应操作。
- 打开VS,创建新项目,选择”动态链接库“
创建了一个名为Dll1的DLL,dllmain.cpp里有vs为我们准备好的DLL程序入口。
我们的执行的代码要在DLL_PROCESS_ATTACH下面写。
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
/*我们的代码,注入DLL后会执行*/
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
先打开头文件pch.h,然后写上
#include <windows.h>
再回到dllmain,加一个弹窗。
case DLL_PROCESS_ATTACH:
/*我们的代码,注入DLL后会执行*/
MessageBox(0,L"成功潜入微信内部!",L"报告主人",NULL);
按F5生成。
打开项目目录下的Debug文件夹,我们可以看到我们生成的Dll1.dll和Dll1.pdb。
DLL注入程序
写完简单的DLL,然后写一个Inject DLL 注入程序(exe),用远程线程注入的方法,把自己的DLL注入到WX进程。
我们再创建一个新项目,选择“控制台程序”,将项目命名为Inject。
方法是先通过WX程序的Pid,调用OpenProcess用可获得的所有权限打开进程,再用VirtualAllocEx在WX进程的地址空间开辟一块内存,调用WriteProcessMemory把我们写的DLL的路径写到WX的内存里。[1]
我们要想办法创建一个远程线程(CreateRemoteThreadEx),让线程执行“LoadLibrary"让微信载入我们的DLL。我们不能直接&LoadLibrary取到函数地址然后传过去让线程执行,因为我们的注入程序的LoadLibrary地址和WX地址空间的LoadLibrary地址不一致。所以我们要用GetProcAddress获取LoadLibrary的地址。
完整代码如下:
int main() {
DWORD pid = 0;
scanf("%d",pid);
HANDLE hprocess = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
if (!hprocess) {
std::cout << "can not get handle" << std::endl;
return 1;
}
SIZE_T PathSize = (strlen(DLLPath) + 1) * sizeof(TCHAR);
LPVOID StartAddress = VirtualAllocEx(hprocess, NULL, PathSize, MEM_COMMIT, PAGE_READWRITE);
if (!StartAddress) {
std::cout << "开辟内存失败" << std::endl;
return 1;
}
if (!WriteProcessMemory(hprocess, StartAddress, DLLPath, PathSize, NULL)) {
std::cout << "无法写入DLL路径" << std::endl;
return 1;
}
PTHREAD_START_ROUTINE pfnStartAddress = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "LoadLibraryA");
if (!pfnStartAddress) {
std::cout << "无法获取函数地址" << std::endl;
return 1;
}
HANDLE hThread = CreateRemoteThreadEx(hprocess, NULL, NULL, pfnStartAddress, StartAddress, NULL, NULL, NULL);
if (!hThread) {
std::cout << "创建线程失败" << std::endl;
return 1;
}
//WaitForSingleObject(hThread, INFINITE);//等待DLL结束
std::cout << "注入成功!\n";
CloseHandle(hThread);
CloseHandle(hprocess);
return 0;
}
然后生成。
登录WX,我们再在cmd输入tasklist,找到WeChat.exe,这个WX的主进程,记下PID,之后运行我我们写的Inject.exe,输入pid。
成功显示,任务栏下方还光明正大的表示成WX的图标,真是血统正宗!
还是来更新一下,做个预告吧。
上面我们让我们的DLL注入到WX里了,这相当于我们光明正大的闯进了他的房子,可以为所欲为!
是的,我们的DLL可以像操作自己的内存一样,读取修改WX的内存,甚至调用和修改他的执行代码!
接下来会以获取到用户信息,如昵称,WX号,电话号码,头像等,讲怎么读取他的内存。
经评论区知友好心提醒,怕被抓,所以#define WX 微信
我又回来啦!
DLL读取用户信息
登录微信后,打开CE,添加微信。
将Value Type改成String,然后输入我们的微信号,一定要一字符不差。
然后first scan扫描,会发现两个绿色的地址。绿色就代表着这个地址的相对位置是不变的,因为我们的微信号、手机号这些,登录之后就不会变化,所以这两个地址符合我们的条件。把他们添加到下栏。
鼠标悬停在上面可以看到,如果你的绿色地址和我一样是一个dll加一个十六进制数,那么后面的0x1D29B60就是我们要找的偏移量。我们可以用WeChatWin.dll基址加上偏移量,就能得出每次运行微信后,微信号的地址。
如果你只是个绿色的地址,那就点击add address manually,输入WeChatWin.dll,然后OK,下栏会多出一个以4个0结尾的地址,这就是这次启动微信WeChatWin.dll的值。
打开计算器,选程序员模式,换到十六进制,用刚刚的一个绿色地址和这个值相减,得出的数值便是偏移。
得到偏移后,找个踏实的地方记下来,以免丢失,又要重新来过。可以直接define到我们的DLL源码里。
用同样方法可以找出微信昵称和电话号码、微信头像什么的。
所以,要获取微信号的地址,只要获取WeChatWin模块基址和偏移然后相加,我们已经找到偏移,怎么让dll知道基址呢?
因为这会我们的DLL已经注入进去,是和WeChatWin.dll等同属一个进程,所以我们可以直接调用GetModuleHandle:
GetModuleHandle(L"WeChatWin.dll");
为了方便易理解,我们封装成函数:
HMODULE GetWechatWin() {
return GetModuleHandle(L"WeChatWin.dll");
}
现在就可以计算出微信号的地址:
pwxid = (DWORD)hModule + WXIDOFFSET;
pphone = (DWORD)hModule + PHONEOFFSET;
然后难点来了,虽然得到了地址,但它是一串DWORD,怎么转换成指针呢。
因为我是从Python入门,没有强制转换这个概念,所以脑筋转不过来。
wxid = (char*)pwxid;
phone = (char*)pphone;
把DWORD强制转换成一个指向char字符串的指针,我们真正就得到了微信号。
来,开个弹窗看看找没找对:
MessageBoxA(0,wxid,0,0);
对了,忘了说,前面wxid和Phone两个char*不是要先定义再使用的嘛,但是呢你在case下面定义,vs就会提示说wxid的定义被跳过,所以这些数据要在switch外定义好,你可以在DllMain函数下面定义初始化,也可以全局。
接下来会说下发送消息。
我一开始是先选发送消息的,因为看着汇编代码比较简单。但是写好了注入进去之后调用call,不是让微信异常终止,就是没错误但调用不了,用OD和VS都调试不出个所以然,所以就暂时放弃,又去hook接收消息,虽然复杂,但好理解,最后成功了。然后回过头来重捋一遍发送消息,才搞定,但始终没清楚一开始为什么会不行,是什么问题导致的。
但能用就行了,管他呢。
之后的一些内容可能会分开几篇文章来写,全堆到这一篇的话,又难维护又难阅读。
Dll1发送消息函数
下面这篇是发送消息的分析教程:
C++ DLL注入微信实现自动接收、发送消息之调用发送callPython获取用户信息
为了让python调用,实现注入DLL,我又新建了一个DLL项目名为InjectDll,把前面的DLL注入程序(Inject.exe)的代码复制过来,然后让Python ctypes载入InjectDll就可以注入,实现Python和注入进WX的DLL沟通。
然而一大堆的函数,复制来还得重新调整,因为数据类型问题很难调用,所以我就放弃了。
原本最长的注入函数,被我改成了:
void injectdll() {
system("D:\\vsproject\\Inject\\Debug\\Inject.exe");
}
或许这才是真正的优雅。
内存映射传递数据
重点是通信,管他是怎么注入的,进去了就行。
然后用内存映射文件让里面的DLL把用户信息传出来。
在Dll1里新建一个cpp源文件,名为shareMsg.cpp[2]。函数有:
int createMapping(PCTSTR pszPathname,PTSTR mapname) {
HANDLE s_hFileMap = CreateFileMapping(pszPathname == NULL ? INVALID_HANDLE_VALUE : CreateFile(pszPathname, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL), NULL, PAGE_READWRITE, 0, 8 * 1024, mapname);
if (s_hFileMap != NULL) {
if (GetLastError() == ERROR_ALREADY_EXISTS) {
//MessageBox(NULL, L"Mapping already exists - not created.", 0, 0);
CloseHandle(s_hFileMap);
return 1;
}
else {
PVOID pView = MapViewOfFile(s_hFileMap, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
if (pView != NULL) {
UnmapViewOfFile(pView);
return 0;
}
else {
//MessageBox(NULL, L"Can't map view of file.",0,0);
return 2;
}
}
}
else {
//MessageBox(NULL, L"Can't create file mapping.", 0, 0);
return 3;
}
}
创建Mapping,如果没有文件名会用-1。文件创建的比较大,因为wx的一些特殊消息比如动画表情,图片,链接等,是以xml的形式呈现的。
int share(PTSTR mapname,PTSTR source, rsize_t sourceSize) {
HANDLE hFileMapT = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, mapname);
if (hFileMapT != NULL) {
PVOID pView = MapViewOfFile(hFileMapT, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
if (pView != NULL) {
wchar_t null[0x1000] = { 0 };
wmemcpy_s((PTSTR)pView, 8 * 1024, null, 0x1000);
wmemcpy_s((PTSTR)pView, 8 * 1024, source, sourceSize);
UnmapViewOfFile(pView);
return 0;
}
else { //MessageBox(NULL, L"can't map view.", 0, 0);
return 1;
}
CloseHandle(hFileMapT);
}
else {
//MessageBox(NULL, L"can't open mapping.", 0, 0);
return 2;
}
}
写入mapping。
PTSTR readMapping(PCTSTR mapname, PTSTR buff, const rsize_t buffSize) {
HANDLE hFileMapT = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, mapname);
if (hFileMapT != NULL) {
PVOID pView = MapViewOfFile(hFileMapT, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
if (pView != NULL) {
rsize_t pViewSize = _tcslen((PTSTR)pView);
wmemcpy_s(buff, buffSize, (PTSTR)pView, buffSize > pViewSize ? pViewSize + 1 : buffSize);
UnmapViewOfFile(pView);
return buff;
}
else { //MessageBox(NULL, L"can't map view.", 0, 0);
return NULL;
}
CloseHandle(hFileMapT);
}
else {
//MessageBox(NULL, L"can't open mapping.", 0, 0);
return NULL;
}
}
读Mapping,虽然没用到,但还是写出来吧。
好,然后在DllMain处,createmapping.
createMapping(L"C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python38\\wechat\\userdata.dat", (PTSTR)L"UserData");
因为要传递用户信息,和接收消息内容,所以要创建多个内存映射,第一个参数最好是个数据文件,而不要写NULL。
然后拼接用户信息:
strcat_s(userdata, 0x40, wxid);
strcat_s(userdata, 0x40, "\n");
strcat_s(userdata, 0x40, phone);
然后分享:
if (share((PTSTR)L"UserData", (PTSTR)userdata, 0x40) != 0)
MessageBox(0, L"userdata lose", 0, 0);
写入方准备好了,之后是Python的读取。
在InjectDll里加上函数:
LPSTR readMappingA(LPCSTR mapname, LPSTR buff, const rsize_t buffSize) {
HANDLE hFileMapT = OpenFileMappingA(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, mapname);
if (hFileMapT != NULL) {
PVOID pView = MapViewOfFile(hFileMapT, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
if (pView != NULL) {
rsize_t pViewSize = strlen((LPSTR)pView);
memcpy_s(buff, buffSize, (LPSTR)pView, buffSize > pViewSize ? pViewSize + 1 : buffSize);
UnmapViewOfFile(pView);
return buff;
}
else { //MessageBox(NULL, L"can't map view.", 0, 0);
return NULL;
}
CloseHandle(hFileMapT);
}
else {
//MessageBox(NULL, L"can't open mapping.", 0, 0);
return NULL;
}
}
让其可以导出:
extern "C"{
__declspec(dllexport) LPSTR readMappingA(LPCSTR mapname, LPSTR buff, const rsize_t buffSize);
}
创建一个Python项目,名为wechat。
在wechat.py中,
注入DLL:
from ctypes import *
inject_dll = windll.LoadLibrary("D:\\vsproject\\InjectDll\\x64\\Debug\\InjectDll.dll")
获取用户信息的函数:
def getuserdata(self):
inject_dll.readMappingA.restype = c_char_p
buff = create_string_buffer(1000)
x=inject_dll.readMappingA(c_char_p(bytes("UserData","utf-8")),buff,len(buff))
#print(x)
x=x.decode('utf-8').split('\n')
return x
Py与Dll1管道通信
在发送消息这篇中,我们在DLL内部实现了一个发送WX消息的函数
void SendWechatMessage(wchar_t* wxid, wchar_t* msg);
在DLL内部调用就能发送消息。但是怎么让外部程序调用?把DLL注入进去之后,就不和我们一个进程了,我们调用不了DLL里面的函数。
所以只能靠通信了,让DLL进去后开个循环,一直监听我们的消息,一有消息就执行相应操作。去网上查了查进程间通信的方式,有内存映射文件,信号,管道,套接字等,粗看觉得管道最直接简单,就选了命名管道。
觉得管道比较适合面向对象编程,本来我的代码就已经够乱了,不能再乱下去,顺便学习下C++ class,就打算写个pipe类。
去MSDN翻了翻,发现有CreateNamedPipe创建管道的函数,有WaitNamedPipe等待,和ConnectNamedPipe连接。
所以分两个类来写吧,服务器和客户端。
class Serverpipe {
public:
HANDLE h_Pipe;
bool create() {
h_Pipe = CreateNamedPipe(
TEXT("\\\\.\\Pipe\\mypipe"), //管道名字
PIPE_ACCESS_DUPLEX, //管道类型
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, //管道参数
PIPE_UNLIMITED_INSTANCES, //管道能创建的最大实例数量
0, //输出缓冲区的长度 0表示默认
0, //输入缓冲区的长度 0表示默认
NMPWAIT_WAIT_FOREVER/*NMPWAIT_USE_DEFAULT_WAIT*/, //超时时间
NULL);
if (h_Pipe == INVALID_HANDLE_VALUE)
{
MessageBox(0, L"Failed to CreateNamedPipe!", 0, 0);
return false;
}
return true;
}
DWORD connect() {
if (ConnectNamedPipe(h_Pipe, NULL) == NULL) //连接,等待
{
if (GetLastError() == ERROR_PIPE_CONNECTED) {
//MessageBox(0, L"我还没准备好,先别进来!", 0, 0);
return ERROR_PIPE_CONNECTED;
}
MessageBox(0, L"Failed to Connect!", 0, 0);
return FALSE;
}
else
{
return TRUE;
}
}
DWORD read(wchar_t* buff,DWORD nNumberOfBytesToWrite) {
DWORD len = 0;
if (ReadFile(h_Pipe, buff, nNumberOfBytesToWrite, &len, NULL) == FALSE) //接收客户端
{
//wchar_t error[100];
//swprintf_s(error, 100, L"错误代码为0x%x", GetLastError());
//MessageBox(0, error, L"Failed to read data!", 0);
return FALSE/*GetLastError()*/;
}
return len;
}
DWORD write(wchar_t* buff,DWORD nNumberOfBytesToWrite) {
DWORD len_ = 0;
WriteFile(h_Pipe, buff, nNumberOfBytesToWrite, &len_, 0); //向客户端发送内容}
return len_;
}
DWORD close() {
return CloseHandle(h_Pipe);
}
};
现在就可以在dllmain.cpp中,创建一个实例。
Serverpipe pipe;
然后,
wchar_t* senddata = new wchar_t[0x3000];
wchar_t seps[] = L"|cut|";
wchar_t* token1 = NULL;
wchar_t* token2 = NULL;
wchar_t* next_token1 = NULL;
wchar_t* next_token2 = NULL;
wchar_t Wxid[20] = { 0 };
wchar_t *Msg = new wchar_t[0x3000];
因为要传两个参数,发送目标和消息内容,所以读取管道内容后,以"|cut|"为分割标记,用strok截断字符串,标记之前作为发送目标,标记之后作为发送内容,也算是一种解析吧。[3]
在DllMain里,
pipe.create();
if(pipe.connect()!=0){
while (true) {
memset(senddata, '\0', 0x3000);
while (pipe.read(senddata, 0x3000) == 0) {}
_tcscpy_s(Wxid, 20, _tcstok_s(senddata, seps, &next_token1));
_tcscpy_s(Msg, 0x3000, _tcstok_s(NULL, seps, &next_token1));
MessageBox(0, Msg, Wxid, 0);
SendWechatMessage(Wxid, Msg);
}
}
然后我们再给InjectDll写上客户端pipe。
class Clientpipe{
public:
HANDLE h_Pipe;
DWORD connect() {
bool bRet = WaitNamedPipe(TEXT("\\\\.\\Pipe\\mypipe"), NMPWAIT_WAIT_FOREVER);
if (!bRet)
{
MessageBox(0, L"Failed to connect pipeline!", 0, 0);
return -1;
}
h_Pipe = CreateFile( //管道属于一种特殊的文件
TEXT("\\\\.\\Pipe\\mypipe"), //文件名字
GENERIC_READ | GENERIC_WRITE, //文件模式
0, //是否共享
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, //文件属性(只读,默认...)NORMAL 为默认属性
NULL);
if (h_Pipe == INVALID_HANDLE_VALUE)
{
//MessageBox(0, L"Failed to CreateFile pipeline file!", 0, 0);
return FALSE;
}
return TRUE;
}
DWORD read(wchar_t* buff, DWORD nNumberOfBytesToWrite) {
DWORD len = 0;
if (ReadFile(h_Pipe, buff, nNumberOfBytesToWrite, &len, NULL) == FALSE) //接收客户端发送的内容
{
//wchar_t error[100];
//swprintf_s(error, 100, L"错误代码为0x%x", GetLastError());
//MessageBox(0, error, L"Failed to read data!", 0);
return GetLastError();
}
return len;
}
DWORD write(wchar_t* buff, DWORD nNumberOfBytesToWrite) {
DWORD len_ = 0;
if (WriteFile(h_Pipe, buff, nNumberOfBytesToWrite, &len_, 0) == FALSE)
return GetLastError();//向客户端发送内容}
return len_;
}
};
生成后,给Python导入,却发现Python貌似根本用不了这个C++类诶。。。
几番折腾还是导出不了,
见知乎上有大佬直接写两个函数,一个创建类实例并返回指针,一个销毁。然后导出两个函数。
我就干脆把class去掉了。
HANDLE h_Pipe;
DWORD connect() {
bool bRet = WaitNamedPipe(TEXT("\\\\.\\Pipe\\mypipe"), NMPWAIT_WAIT_FOREVER);
if (!bRet)
{
MessageBox(0, L"Failed to connect pipeline!", 0, 0);
return -1;
}
h_Pipe = CreateFile( //管道属于一种特殊的文件
TEXT("\\\\.\\Pipe\\mypipe"), //文件名字
GENERIC_READ | GENERIC_WRITE, //文件模式
0, //是否共享
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, //文件属性(只读,默认...)NORMAL 为默认属性
NULL);
if (h_Pipe == INVALID_HANDLE_VALUE)
{
//MessageBox(0, L"Failed to CreateFile pipeline file!", 0, 0);
return FALSE;
}
return TRUE;
}
DWORD read(wchar_t* buff, DWORD nNumberOfBytesToWrite) {
DWORD len = 0;
if (ReadFile(h_Pipe, buff, nNumberOfBytesToWrite, &len, NULL) == FALSE) //接收客户端发送的内容
{
//wchar_t error[100];
//swprintf_s(error, 100, L"错误代码为0x%x", GetLastError());
//MessageBox(0, error, L"Failed to read data!", 0);
return GetLastError();
}
return len;
}
DWORD write(wchar_t* buff, DWORD nNumberOfBytesToWrite) {
DWORD len_ = 0;
if (WriteFile(h_Pipe, buff, nNumberOfBytesToWrite, &len_, 0) == FALSE)
return GetLastError();//向客户端发送内容}
return len_;
}
让类方法变成全局函数。
然后逐个导出:
extern "C"{
__declspec(dllexport) DWORD connect();
__declspec(dllexport) DWORD read(wchar_t* buff, DWORD nNumberOfBytesToWrite);
__declspec(dllexport) DWORD write(wchar_t* buff, DWORD nNumberOfBytesToWrite);
}
OK,搞定。
Python发送消息函数
回到wechat.py,写一个发送消息的函数:
def send(self,msg,wxid=None,name=None,findtime=1.8):
if wxid:
msg=wxid+'|cut|'+msg
buff = create_unicode_buffer(msg)
x=inject_dll.write(buff,len(buff)*2)
elif name:
self.find(name)
self.write(msg)
pag.hotkey('alt', 's')
return True
return x
如果传入了wxid也就是发送目标,就会构造发送目标+发送内容的字符串,然后写入管道,管道对面的Dll1监听到后立马进行发送操作,函数最后返回写入管道的字节数。如果只输入了好友昵称,就搜索找到对应好友聊天框,发送窗口消息+模拟按键发送。
多线程解决无响应
于是,感觉大功告成的我激动地打开IDLE,调用send函数,然而wx却是
无 响 应 。。
这当头一棒,打得我措手不及。
回想刚写的代码,就只有管道和接收消息循环。管道是不会出什么大问题的,那肯定是Dll1里的循环了。当时想着,写下无限循环,最多卡着当前的线程,不会影响到整个进程,其他GUI组件应该还能用。或许真有问题吧。
于是我回到Dll1,把最后的while循环整个包装入一个函数里,
void waitmsg() {
while (true) {
memset(senddata, '\0', 0x3000);
while (pipe.read(senddata, 0x3000) == 0) {}
_tcscpy_s(Wxid, 20, _tcstok_s(senddata, seps, &next_token1));
_tcscpy_s(Msg, 0x3000, _tcstok_s(NULL, seps, &next_token1));
MessageBox(0, Msg, Wxid, 0);
SendWechatMessage(Wxid, Msg);
}
}
然后在DllMain调用此函数。
重启wx,ctrl+F6 IDLE,再send。
诶哟,成功发送了!
来让我再发几条~
第二次调用send,WX又卡死了。。
看来要不卡死,只能并发了。
#include <thread>
thread th(waitmsg);
创建一个线程th,线程执行函数waitmsg。
把DllMain最后的
waitmsg();
改为
thread th(waitmsg);
这样,到最后,就会创建新线程,单独执行while循环,这样就不会影响主线程了。
重新生成,VS却提示“th的初始化被标签case跳过”。
可是这个线程实例,我什么时候初始化它,它就什么时候开始执行,你不给我在里面初始化,那我只能在外部提前初始化,管道没连接就开始了监听,肯定会引发错误啊。
不管了,我非要在里面初始化类实例。于是我又写了一个函数,
void _th() {
thread th(waitmsg);
}
然后在DllMain里的最后改为
_th();
生成,vs不报错了。
但是想到在函数里创建的变量什么的,函数执行完毕会被销毁哦,保险起见,加个static
void _th() {
static thread th(waitmsg);
}
OK。再次打开IDLE,发送消息,成了!
成了!
成了!
至此,终于封装好了发送wx消息的Python函数。
Dll1接收消息Hook
下面是HOOK接收消息
C++ DLL注入微信hook实现自动接收消息具体的找函数和写代码hook已经单独写在上文。
Python获取新消息
在接收消息那篇文章中,我们写了响应函数,一有消息就会内存映射并弹窗显示,现在Python只需要读内存映射就行了。
在我们写的InjectDll中有读取内存映射文件的函数readMapping,我们上面已经让Python导入了InjectDll,现在就用它的函数。
这里涉及到ctypes库,比较繁杂,建议先看一下文档,再继续。
inject_dll.readMapping.restype = c_wchar_p
buff = create_unicode_buffer(5000)
msg = inject_dll.readMapping("NewMessageLog",buff,5000)
设置readMapping函数的返回值类型为cwchar指针,然后创建buff传参。这里的buff相当于c++ 的
wchar_t buff[5000]={0};
包装成函数:
def getmsg(self):
inject_dll.readMapping.restype = c_wchar_p
buff = create_unicode_buffer(5000)
msg = inject_dll.readMapping("NewMessageLog",buff,5000)
for i in range(-1, -20, -1):
if msg[i] == '}':
j = i
if msg[i] == '{':
k = i
break
msgtype = ''
try:
for i in range(k + 1, j):
msgtype = msgtype + msg[i]
except UnboundLocalError:
msgtype = '长链接'
return {"text":msg,"wxid":None,"type":msgtype}
msgwxid = msgtype.split('[')[1].replace(']','')
msgtype = msgtype.split('[')[0]
msg = msg[::-1].replace(msgtype[::-1],'')[::-1]
msg = msg[::-1].replace(msgwxid[::-1], '')[::-1].replace('{[]}','')
return {"text":msg,"wxid":msgwxid,"type":msgtype}
到这里已经写了几个Python函数,为了方便管理和日后调用,建议把它们包装成一个Wechat类。
以后就可以
>>> import wechat
>>> myweixin = wechat.Wechat()
...
>>> myweixin.send(...)
...
>>> myweixin.getmsg()
...
也可以给其他程序调用。
自定义新消息响应函数
我们现在可以获取到最新一条的消息了,但是我还想要能自定义一个回调函数,每有新消息,就让程序调用我们的处理函数。
要及时响应,就要开循环去监听对吧,我们在写DLL的时候试过了,直接开while循环就会卡死做不了其他事情,对于Python这个动态语言肯定是自断功力的。吃一堑长一智,我们同样可以用多线程的方法解决这个问题。
Python中的多线程库有threading,这是标准库。
导出线程类:
from threading import Thread
继承,写子类:
class myThread (Thread):
def __init__(self, threadID, name, getmsgfunc,cbfunc):
Thread.__init__(self)
self.running = True
self.threadID = threadID
self.name = name
self.getmsgfunc = getmsgfunc
self.cbfunc = cbfunc
def run(self):
while True:
if self.running:
msglist = self.getmsgfunc()
if msglist:
self.cbfunc(msglist)
time.sleep(1)
类接收这四个参数,其中threadID和name是我们自己设定的,用来区分。之后是两个函数引用,分别是获取消息的函数和我们自定义的回调函数。之后子线程开循环一直get消息然后将消息列表传参给回调函数。
这时注意了,如果我们的getmsg函数一直返回消息的话,循环就会一直执行回调函数,因为他不知道这是不是最新消息了,消息是否被处理过了。所以我们要做好区分,让新消息只能接收一次。下一次就return False。
调整一下:
def getmsg(self):
inject_dll.readMapping.restype = c_wchar_p
buff = create_unicode_buffer(5000)
msg = inject_dll.readMapping("NewMessageLog",buff,5000)
if not msg:
return False
buff = create_unicode_buffer(50)
inject_dll.writeMapping("NewMessageLog",buff,50)
for i in range(-1, -20, -1):
if msg[i] == '}':
j = i
if msg[i] == '{':
k = i
break
msgtype = ''
try:
for i in range(k + 1, j):
msgtype = msgtype + msg[i]
except UnboundLocalError:
msgtype = '长链接'
return {"text":msg,"wxid":None,"type":msgtype}
msgwxid = msgtype.split('[')[1].replace(']','')
msgtype = msgtype.split('[')[0]
msg = msg[::-1].replace(msgtype[::-1],'')[::-1]
msg = msg[::-1].replace(msgwxid[::-1], '')[::-1].replace('{[]}','')
return {"text":msg,"wxid":msgwxid,"type":msgtype}
这样,我们每获取一次消息,就把内存映射文件清空,表明我们已经收到了这个消息,下次再读取就会读到None,表明已经没有新消息了。
感觉我这getmsg后面这么长一段解析字符串的代码,可以用正则去匹配哦。大家可以自己改进一下,我也懒得改了。
th = myThread(2, "hook", self.getmsg, self.hookcallback)
self.th = th
print(self.th)
self.th.start()
然后我们可以在wechat类的_init_里start线程。
之后我们可以实时调整callback函数(应该可以,没试过调整)。
然后我们可以:
>>> mywx = wechat.Wechat()
>>> def cb(alist):
print(f'好友{alist["wxid"]}像你发送了这条{alist["type"]}消息: {alist["text]}')
>>> mywx.hookcallback = cb
...
这是最基本的,这个回调大家看怎么用了。
进阶应用
1.手机命令电脑
手机控制电脑,这是个鸡肋的功能,但保不准有什么用,比如工作时暂时离开,向文件传输助手发个shutdown -s就能关机,如果有某些心怀不轨的同事朋友偷偷看我们的电脑,我们可以向文件传输助手发送take Photos命令截图留下证据然后锁屏,还可以发送模拟键盘鼠标操作命令在手机上使用电脑……
甚至给配置个多功能聊天机器人,就可以在文件传输助手查天气聊闲天查资料什么的,(我手机的语音助手太垃了,连GUI界面都没有,和其他手机相比简直就是猪与人的差距)。
不知不觉已经两万多字了,手机端几乎编辑不了了,要卡死,所以后文分几篇文章写。
手机命令电脑之后可以有很多分支,比如自动回复,消息语音播报,我不手把手说了,自己探索吧(安全第一,我选择苟)。
接下来打算把InjectDll这个DLL改成一个Python库的形式,直接Import,不需要又用ctypes载入DLL,不然调用个函数都要几行代码,还无法导出类。
C++给python写扩展库按评论区建议,又来补充上了在群里@人的教程。
C++ DLL注入微信之发送群@消息六、gbox怎么注入文件?
如果您指的是基于盒子的开发平台G-Box,该平台提供了Python SDK和REST API接口,可以通过这些API实现文件的上传和下载。具体的注入文件流程如下:
1.使用G-Box提供的SDK或API进行身份认证,获取token。
2.调用上传接口,将需要注入的文件上传到G-Box的存储系统中。您可以使用类似以下代码的Python代码实现文件上传:
```
import requests
url = "https://api.gboxapps.com/file/upload"
headers = {'Authorization': 'Bearer ' + token}
files = {'file': open('path/to/your/file', 'rb')}
res = requests.post(url, headers=headers, files=files)
```
3.注入文件到应用程序中。在G-Box平台中,您可以使用Pipeline对多个应用程序进行编排和组合。具体来说,您可以在Pipeline定义里,使用"inputs"来指定输入数据,将上传的文件作为Pipeline的输入数据。然后将Pipeline的输出数据作为需要注入文件的应用程序的输入数据,从而实现文件的注入。
请注意,具体的注入流程可能因具体应用场景而有所不同,需要根据实际情况进行适当的调整。
七、关于PHP读写文件?
相关php函数:fopen()打开文件。格式如:fopen("文件路径","r")。fopen()函数有参数第一个参数要指明文件,第二个参数可以是r,w等,读文件时就可以是r,写文件时可以是w。fwrite()和 fputs()写文件。fclose()关闭文件。fgets()读取记录。最常用的是以上这些函数。
八、怎么创建PHP文件?
在桌面空白处单击右键->新建->文本文件.双击打开此文本文件后,在里面输入PHP代码,输入完后,选择文件->另存为...这里输入你的PHP文件名,扩展名为PHP.当然你也可以用网页编辑工具,更直观和方便,如:Dreamweaver,直接新建一个网页文件,选择PHP文件就OK了.
九、php文件用什么软件打开?
垃圾课程
十、如何判断PHP源码是否存在SQL注入漏洞?
判断是否存在SQL注入首先找到可能的注入点;比如常见的get,post,甚至cookie,传递参数到PHP,然后参数被拼接到SQL中,如果后端接收参数后没有进行验证过滤,就很可能会出现注入。比如xxx.com?id=321,id就很可能是注入点。
说白了就是不要相信用户输入,对用户可控的参数进行严格校验。注意是严格校验!简单的去空格,或者是特殊字符替换很容易绕过。
如果已经有原码,可以进行代码审计,进行逐一排查。也可以搭建本地环境使用类似于sqlmap这样的自动化工具进行可以链接的检测。
个人理解仅供参考,如有偏颇望批评指正!
热点信息
-
在Python中,要查看函数的用法,可以使用以下方法: 1. 使用内置函数help():在Python交互式环境中,可以直接输入help(函数名)来获取函数的帮助文档。例如,...
-
一、java 连接数据库 在当今信息时代,Java 是一种广泛应用的编程语言,尤其在与数据库进行交互的过程中发挥着重要作用。无论是在企业级应用开发还是...
-
一、idea连接mysql数据库 php connect_error) { die("连接失败: " . $conn->connect_error);}echo "成功连接到MySQL数据库!";// 关闭连接$conn->close();?> 二、idea连接mysql数据库连...
-
要在Python中安装modbus-tk库,您可以按照以下步骤进行操作: 1. 确保您已经安装了Python解释器。您可以从Python官方网站(https://www.python.org)下载和安装最新版本...