WeChatFerry/WeChatFerry/spy/funcs.cpp
2023-11-26 22:36:41 +08:00

266 lines
5.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma warning(disable : 4244)
#include "framework.h"
#include <filesystem>
#include <fstream>
#include "exec_sql.h"
#include "funcs.h"
#include "log.h"
#include "spy_types.h"
#include "util.h"
#define HEADER_PNG1 0x89
#define HEADER_PNG2 0x50
#define HEADER_JPG1 0xFF
#define HEADER_JPG2 0xD8
#define HEADER_GIF1 0x47
#define HEADER_GIF2 0x49
using namespace std;
namespace fs = std::filesystem;
extern bool gIsListeningPyq;
extern WxCalls_t g_WxCalls;
extern DWORD g_WeChatWinDllAddr;
typedef struct RawVector {
DWORD start;
DWORD finish;
DWORD end;
} RawVector_t;
static string get_key(uint8_t header1, uint8_t header2, uint8_t *key)
{
// PNG?
*key = HEADER_PNG1 ^ header1;
if ((HEADER_PNG2 ^ *key) == header2) {
return ".png";
}
// JPG?
*key = HEADER_JPG1 ^ header1;
if ((HEADER_JPG2 ^ *key) == header2) {
return ".jpg";
}
// GIF?
*key = HEADER_GIF1 ^ header1;
if ((HEADER_GIF2 ^ *key) == header2) {
return ".gif";
}
return ""; // 错误
}
string DecryptImage(string src, string dir)
{
ifstream in(src.c_str(), ios::binary);
if (!in.is_open()) {
LOG_ERROR("Failed to read file {}", src);
return "";
}
filebuf *pfb = in.rdbuf();
size_t size = pfb->pubseekoff(0, ios::end, ios::in);
pfb->pubseekpos(0, ios::in);
vector<char> buff;
buff.reserve(size);
char *pBuf = buff.data();
pfb->sgetn(pBuf, size);
in.close();
uint8_t key = 0x00;
string ext = get_key(pBuf[0], pBuf[1], &key);
if (ext.empty()) {
LOG_ERROR("Failed to get key.");
return "";
}
for (size_t i = 0; i < size; i++) {
pBuf[i] ^= key;
}
string dst = "";
if (!dir.empty()) {
dst = (dir.back() == '\\' || dir.back() == '/') ? dir : (dir + "/");
}
try {
dst += fs::path(src).stem().string() + ext;
replace(dst.begin(), dst.end(), '\\', '/');
} catch (...) {
LOG_ERROR("Unknow exception.");
return "";
}
ofstream out(dst.c_str(), ios::binary);
if (!out.is_open()) {
LOG_ERROR("Failed to write file {}", dst);
return "";
}
out.write(pBuf, size);
out.close();
return dst;
}
static int GetFirstPage()
{
int rv = -1;
DWORD pyqCall1 = g_WeChatWinDllAddr + g_WxCalls.pyq.call1;
DWORD pyqCall2 = g_WeChatWinDllAddr + g_WxCalls.pyq.call2;
char buf[0xB44] = { 0 };
__asm {
pushad;
call pyqCall1;
push 0x1;
lea ecx, buf;
push ecx;
mov ecx, eax;
call pyqCall2;
mov rv, eax;
popad;
}
return rv;
}
static int GetNextPage(uint64_t id)
{
int rv = -1;
DWORD pyqCall1 = g_WeChatWinDllAddr + g_WxCalls.pyq.call1;
DWORD pyqCall3 = g_WeChatWinDllAddr + g_WxCalls.pyq.call3;
RawVector_t tmp = { 0 };
__asm {
pushad;
call pyqCall1;
lea ecx, tmp;
push ecx;
mov ebx, dword ptr [id + 0x04];
push ebx;
mov edi, dword ptr [id]
push edi;
mov ecx, eax;
call pyqCall3;
mov rv, eax;
popad;
}
return rv;
}
int RefreshPyq(uint64_t id)
{
if (!gIsListeningPyq) {
LOG_ERROR("没有启动朋友圈消息接收参考enable_receiving_msg");
return -1;
}
if (id == 0) {
return GetFirstPage();
}
return GetNextPage(id);
}
int DownloadAttach(uint64_t id, string thumb, string extra)
{
int status = -1;
uint64_t localId;
uint32_t dbIdx;
if (GetLocalIdandDbidx(id, &localId, &dbIdx) != 0) {
LOG_ERROR("Failed to get localId, Please check id: {}", to_string(id));
return status;
}
char buff[0x2D8] = { 0 };
DWORD dlCall1 = g_WeChatWinDllAddr + g_WxCalls.da.call1;
DWORD dlCall2 = g_WeChatWinDllAddr + g_WxCalls.da.call2;
DWORD dlCall3 = g_WeChatWinDllAddr + g_WxCalls.da.call3;
DWORD dlCall4 = g_WeChatWinDllAddr + g_WxCalls.da.call4;
DWORD dlCall5 = g_WeChatWinDllAddr + g_WxCalls.da.call5;
DWORD dlCall6 = g_WeChatWinDllAddr + g_WxCalls.da.call6;
__asm {
pushad;
pushfd;
lea ecx, buff;
call dlCall1;
call dlCall2;
push dword ptr [dbIdx];
lea ecx, buff;
push dword ptr [localId];
call dlCall3;
add esp, 0x8;
popfd;
popad;
}
DWORD type = GET_DWORD(buff + 0x38);
string save_path = "";
string thumb_path = "";
switch (type) {
case 0x03: { // Image: extra
save_path = extra;
break;
}
case 0x3E:
case 0x2B: { // Video: thumb
thumb_path = thumb;
save_path = fs::path(thumb).replace_extension("mp4").string();
break;
}
case 0x31: { // File: extra
save_path = extra;
break;
}
default:
break;
}
// 创建父目录,由于路径来源于微信,不做检查
fs::create_directory(fs::path(save_path).parent_path().string());
if (fs::exists(save_path)) { // 不重复下载
return 0;
}
wstring wsSavePath = String2Wstring(save_path);
wstring wsThumbPath = String2Wstring(thumb_path);
WxString wxSavePath(wsSavePath);
WxString wxThumbPath(wsThumbPath);
int temp = 1;
memcpy(&buff[0x19C], &wxThumbPath, sizeof(wxThumbPath));
memcpy(&buff[0x1B0], &wxSavePath, sizeof(wxSavePath));
memcpy(&buff[0x29C], &temp, sizeof(temp));
__asm {
pushad;
pushfd;
call dlCall4;
push 0x1;
push 0x0;
lea ecx, buff;
push ecx;
mov ecx, eax;
call dlCall5;
mov status, eax;
lea ecx, buff;
push 0x0;
call dlCall6;
popfd;
popad;
}
return status;
}