diff --git a/.editorconfig b/WeChatFerry/.editorconfig similarity index 85% rename from .editorconfig rename to WeChatFerry/.editorconfig index ace811e..46da929 100644 --- a/.editorconfig +++ b/WeChatFerry/.editorconfig @@ -1,7 +1,7 @@ -[*] -end_of_line = lf -charset = utf-8-bom -trim_trailing_whitespace = true -insert_final_newline = true -indent_style = space +[*] +end_of_line = lf +charset = utf-8-bom +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space indent_size = 4 \ No newline at end of file diff --git a/WeChatFerry.sln b/WeChatFerry/WeChatFerry.sln similarity index 98% rename from WeChatFerry.sln rename to WeChatFerry/WeChatFerry.sln index dde3cd4..2044e47 100644 --- a/WeChatFerry.sln +++ b/WeChatFerry/WeChatFerry.sln @@ -1,49 +1,49 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.32802.440 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spy", "spy\spy.vcxproj", "{4DE80B82-5F6A-4C4C-9D16-1574308110FA}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdk", "sdk\sdk.vcxproj", "{ABFCB647-137F-478B-A73E-F0B1E3ADC215}" - ProjectSection(ProjectDependencies) = postProject - {4DE80B82-5F6A-4C4C-9D16-1574308110FA} = {4DE80B82-5F6A-4C4C-9D16-1574308110FA} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launcher", "launcher\launcher.vcxproj", "{B11ADC6F-20DA-4DEF-A8A0-60374427D4C6}" - ProjectSection(ProjectDependencies) = postProject - {ABFCB647-137F-478B-A73E-F0B1E3ADC215} = {ABFCB647-137F-478B-A73E-F0B1E3ADC215} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wcf", "wcf\wcf.vcxproj", "{02747CE0-AD9F-4812-B019-FCF9867F7514}" - ProjectSection(ProjectDependencies) = postProject - {4DE80B82-5F6A-4C4C-9D16-1574308110FA} = {4DE80B82-5F6A-4C4C-9D16-1574308110FA} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Debug|x86.ActiveCfg = Debug|Win32 - {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Debug|x86.Build.0 = Debug|Win32 - {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x86.ActiveCfg = Release|Win32 - {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x86.Build.0 = Release|Win32 - {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Debug|x86.ActiveCfg = Release|Win32 - {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x86.ActiveCfg = Release|Win32 - {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x86.Build.0 = Release|Win32 - {B11ADC6F-20DA-4DEF-A8A0-60374427D4C6}.Debug|x86.ActiveCfg = Release|Win32 - {B11ADC6F-20DA-4DEF-A8A0-60374427D4C6}.Release|x86.ActiveCfg = Release|Win32 - {B11ADC6F-20DA-4DEF-A8A0-60374427D4C6}.Release|x86.Build.0 = Release|Win32 - {02747CE0-AD9F-4812-B019-FCF9867F7514}.Debug|x86.ActiveCfg = Release|Win32 - {02747CE0-AD9F-4812-B019-FCF9867F7514}.Release|x86.ActiveCfg = Release|Win32 - {02747CE0-AD9F-4812-B019-FCF9867F7514}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {76A678AA-570C-4CB7-B58F-3B2C170ACAC0} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.32802.440 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spy", "spy\spy.vcxproj", "{4DE80B82-5F6A-4C4C-9D16-1574308110FA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdk", "sdk\sdk.vcxproj", "{ABFCB647-137F-478B-A73E-F0B1E3ADC215}" + ProjectSection(ProjectDependencies) = postProject + {4DE80B82-5F6A-4C4C-9D16-1574308110FA} = {4DE80B82-5F6A-4C4C-9D16-1574308110FA} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "launcher", "launcher\launcher.vcxproj", "{B11ADC6F-20DA-4DEF-A8A0-60374427D4C6}" + ProjectSection(ProjectDependencies) = postProject + {ABFCB647-137F-478B-A73E-F0B1E3ADC215} = {ABFCB647-137F-478B-A73E-F0B1E3ADC215} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wcf", "wcf\wcf.vcxproj", "{02747CE0-AD9F-4812-B019-FCF9867F7514}" + ProjectSection(ProjectDependencies) = postProject + {4DE80B82-5F6A-4C4C-9D16-1574308110FA} = {4DE80B82-5F6A-4C4C-9D16-1574308110FA} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Debug|x86.ActiveCfg = Debug|Win32 + {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Debug|x86.Build.0 = Debug|Win32 + {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x86.ActiveCfg = Release|Win32 + {4DE80B82-5F6A-4C4C-9D16-1574308110FA}.Release|x86.Build.0 = Release|Win32 + {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Debug|x86.ActiveCfg = Release|Win32 + {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x86.ActiveCfg = Release|Win32 + {ABFCB647-137F-478B-A73E-F0B1E3ADC215}.Release|x86.Build.0 = Release|Win32 + {B11ADC6F-20DA-4DEF-A8A0-60374427D4C6}.Debug|x86.ActiveCfg = Release|Win32 + {B11ADC6F-20DA-4DEF-A8A0-60374427D4C6}.Release|x86.ActiveCfg = Release|Win32 + {B11ADC6F-20DA-4DEF-A8A0-60374427D4C6}.Release|x86.Build.0 = Release|Win32 + {02747CE0-AD9F-4812-B019-FCF9867F7514}.Debug|x86.ActiveCfg = Release|Win32 + {02747CE0-AD9F-4812-B019-FCF9867F7514}.Release|x86.ActiveCfg = Release|Win32 + {02747CE0-AD9F-4812-B019-FCF9867F7514}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {76A678AA-570C-4CB7-B58F-3B2C170ACAC0} + EndGlobalSection +EndGlobal diff --git a/launcher/Launcher.cpp b/WeChatFerry/launcher/Launcher.cpp similarity index 100% rename from launcher/Launcher.cpp rename to WeChatFerry/launcher/Launcher.cpp diff --git a/launcher/Launcher.h b/WeChatFerry/launcher/Launcher.h similarity index 100% rename from launcher/Launcher.h rename to WeChatFerry/launcher/Launcher.h diff --git a/launcher/Launcher.resx b/WeChatFerry/launcher/Launcher.resx similarity index 100% rename from launcher/Launcher.resx rename to WeChatFerry/launcher/Launcher.resx diff --git a/launcher/icon.ico b/WeChatFerry/launcher/icon.ico similarity index 100% rename from launcher/icon.ico rename to WeChatFerry/launcher/icon.ico diff --git a/launcher/launcher.aps b/WeChatFerry/launcher/launcher.aps similarity index 100% rename from launcher/launcher.aps rename to WeChatFerry/launcher/launcher.aps diff --git a/WeChatFerry/launcher/launcher.rc b/WeChatFerry/launcher/launcher.rc new file mode 100644 index 0000000..7603fbe Binary files /dev/null and b/WeChatFerry/launcher/launcher.rc differ diff --git a/launcher/launcher.vcxproj b/WeChatFerry/launcher/launcher.vcxproj similarity index 100% rename from launcher/launcher.vcxproj rename to WeChatFerry/launcher/launcher.vcxproj diff --git a/launcher/launcher.vcxproj.filters b/WeChatFerry/launcher/launcher.vcxproj.filters similarity index 100% rename from launcher/launcher.vcxproj.filters rename to WeChatFerry/launcher/launcher.vcxproj.filters diff --git a/launcher/launcher.vcxproj.user b/WeChatFerry/launcher/launcher.vcxproj.user similarity index 100% rename from launcher/launcher.vcxproj.user rename to WeChatFerry/launcher/launcher.vcxproj.user diff --git a/launcher/resource.h b/WeChatFerry/launcher/resource.h similarity index 100% rename from launcher/resource.h rename to WeChatFerry/launcher/resource.h diff --git a/rpc/nanopb/pb.h b/WeChatFerry/rpc/nanopb/pb.h similarity index 100% rename from rpc/nanopb/pb.h rename to WeChatFerry/rpc/nanopb/pb.h diff --git a/rpc/nanopb/pb_common.c b/WeChatFerry/rpc/nanopb/pb_common.c similarity index 100% rename from rpc/nanopb/pb_common.c rename to WeChatFerry/rpc/nanopb/pb_common.c diff --git a/rpc/nanopb/pb_common.h b/WeChatFerry/rpc/nanopb/pb_common.h similarity index 100% rename from rpc/nanopb/pb_common.h rename to WeChatFerry/rpc/nanopb/pb_common.h diff --git a/rpc/nanopb/pb_decode.c b/WeChatFerry/rpc/nanopb/pb_decode.c similarity index 100% rename from rpc/nanopb/pb_decode.c rename to WeChatFerry/rpc/nanopb/pb_decode.c diff --git a/rpc/nanopb/pb_decode.h b/WeChatFerry/rpc/nanopb/pb_decode.h similarity index 100% rename from rpc/nanopb/pb_decode.h rename to WeChatFerry/rpc/nanopb/pb_decode.h diff --git a/rpc/nanopb/pb_encode.c b/WeChatFerry/rpc/nanopb/pb_encode.c similarity index 100% rename from rpc/nanopb/pb_encode.c rename to WeChatFerry/rpc/nanopb/pb_encode.c diff --git a/rpc/nanopb/pb_encode.h b/WeChatFerry/rpc/nanopb/pb_encode.h similarity index 100% rename from rpc/nanopb/pb_encode.h rename to WeChatFerry/rpc/nanopb/pb_encode.h diff --git a/rpc/pb_types.h b/WeChatFerry/rpc/pb_types.h similarity index 100% rename from rpc/pb_types.h rename to WeChatFerry/rpc/pb_types.h diff --git a/rpc/pb_util.cpp b/WeChatFerry/rpc/pb_util.cpp similarity index 100% rename from rpc/pb_util.cpp rename to WeChatFerry/rpc/pb_util.cpp diff --git a/rpc/pb_util.h b/WeChatFerry/rpc/pb_util.h similarity index 100% rename from rpc/pb_util.h rename to WeChatFerry/rpc/pb_util.h diff --git a/rpc/proto/wcf.options b/WeChatFerry/rpc/proto/wcf.options similarity index 100% rename from rpc/proto/wcf.options rename to WeChatFerry/rpc/proto/wcf.options diff --git a/rpc/proto/wcf.proto b/WeChatFerry/rpc/proto/wcf.proto similarity index 100% rename from rpc/proto/wcf.proto rename to WeChatFerry/rpc/proto/wcf.proto diff --git a/rpc/tool/nanopb_generator.py b/WeChatFerry/rpc/tool/nanopb_generator.py similarity index 100% rename from rpc/tool/nanopb_generator.py rename to WeChatFerry/rpc/tool/nanopb_generator.py diff --git a/rpc/tool/nanopb_generator.py2 b/WeChatFerry/rpc/tool/nanopb_generator.py2 similarity index 100% rename from rpc/tool/nanopb_generator.py2 rename to WeChatFerry/rpc/tool/nanopb_generator.py2 diff --git a/rpc/tool/platformio_generator.py b/WeChatFerry/rpc/tool/platformio_generator.py similarity index 100% rename from rpc/tool/platformio_generator.py rename to WeChatFerry/rpc/tool/platformio_generator.py diff --git a/rpc/tool/proto/Makefile b/WeChatFerry/rpc/tool/proto/Makefile similarity index 100% rename from rpc/tool/proto/Makefile rename to WeChatFerry/rpc/tool/proto/Makefile diff --git a/rpc/tool/proto/__init__.py b/WeChatFerry/rpc/tool/proto/__init__.py similarity index 100% rename from rpc/tool/proto/__init__.py rename to WeChatFerry/rpc/tool/proto/__init__.py diff --git a/rpc/tool/proto/_utils.py b/WeChatFerry/rpc/tool/proto/_utils.py similarity index 100% rename from rpc/tool/proto/_utils.py rename to WeChatFerry/rpc/tool/proto/_utils.py diff --git a/rpc/tool/proto/google/protobuf/descriptor.proto b/WeChatFerry/rpc/tool/proto/google/protobuf/descriptor.proto similarity index 100% rename from rpc/tool/proto/google/protobuf/descriptor.proto rename to WeChatFerry/rpc/tool/proto/google/protobuf/descriptor.proto diff --git a/rpc/tool/proto/nanopb.proto b/WeChatFerry/rpc/tool/proto/nanopb.proto similarity index 100% rename from rpc/tool/proto/nanopb.proto rename to WeChatFerry/rpc/tool/proto/nanopb.proto diff --git a/rpc/tool/proto/nanopb_pb2.py b/WeChatFerry/rpc/tool/proto/nanopb_pb2.py similarity index 100% rename from rpc/tool/proto/nanopb_pb2.py rename to WeChatFerry/rpc/tool/proto/nanopb_pb2.py diff --git a/rpc/tool/protoc b/WeChatFerry/rpc/tool/protoc similarity index 100% rename from rpc/tool/protoc rename to WeChatFerry/rpc/tool/protoc diff --git a/rpc/tool/protoc-gen-nanopb b/WeChatFerry/rpc/tool/protoc-gen-nanopb similarity index 100% rename from rpc/tool/protoc-gen-nanopb rename to WeChatFerry/rpc/tool/protoc-gen-nanopb diff --git a/rpc/tool/protoc-gen-nanopb-py2 b/WeChatFerry/rpc/tool/protoc-gen-nanopb-py2 similarity index 100% rename from rpc/tool/protoc-gen-nanopb-py2 rename to WeChatFerry/rpc/tool/protoc-gen-nanopb-py2 diff --git a/rpc/tool/protoc-gen-nanopb.bat b/WeChatFerry/rpc/tool/protoc-gen-nanopb.bat similarity index 100% rename from rpc/tool/protoc-gen-nanopb.bat rename to WeChatFerry/rpc/tool/protoc-gen-nanopb.bat diff --git a/rpc/tool/protoc.bat b/WeChatFerry/rpc/tool/protoc.bat similarity index 100% rename from rpc/tool/protoc.bat rename to WeChatFerry/rpc/tool/protoc.bat diff --git a/sdk/SDK.vcxproj b/WeChatFerry/sdk/SDK.vcxproj similarity index 97% rename from sdk/SDK.vcxproj rename to WeChatFerry/sdk/SDK.vcxproj index 8c6146a..d781815 100644 --- a/sdk/SDK.vcxproj +++ b/WeChatFerry/sdk/SDK.vcxproj @@ -1,191 +1,191 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {abfcb647-137f-478b-a73e-f0b1e3adc215} - sdk - 10.0 - - - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - true - Unicode - - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - - - false - - - true - - - false - - - true - x86-windows-static - - - - Level3 - true - WIN32;_DEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - pch.h - - - Windows - true - false - sdk.def - - - - - Level3 - true - true - true - WIN32;NDEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - NotUsing - - - stdcpp17 - $(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include - MultiThreaded - - - Windows - true - true - true - false - sdk.def - - - xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out - - - Copy files - - - - - Level3 - true - _DEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - pch.h - - - Windows - true - false - sdk.def - - - - - Level3 - true - true - true - NDEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - pch.h - - - Windows - true - true - true - false - sdk.def - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {abfcb647-137f-478b-a73e-f0b1e3adc215} + sdk + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + true + x86-windows-static + + + + Level3 + true + WIN32;_DEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + sdk.def + + + + + Level3 + true + true + true + WIN32;NDEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + + + stdcpp17 + $(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include + MultiThreaded + + + Windows + true + true + true + false + sdk.def + + + xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out + + + Copy files + + + + + Level3 + true + _DEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + sdk.def + + + + + Level3 + true + true + true + NDEBUG;SDK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + true + true + false + sdk.def + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sdk/SDK.vcxproj.filters b/WeChatFerry/sdk/SDK.vcxproj.filters similarity index 96% rename from sdk/SDK.vcxproj.filters rename to WeChatFerry/sdk/SDK.vcxproj.filters index 58eff8d..8f8a4a5 100644 --- a/sdk/SDK.vcxproj.filters +++ b/WeChatFerry/sdk/SDK.vcxproj.filters @@ -1,56 +1,56 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - - - 源文件 - - - 源文件 - - - 源文件 - - - 源文件 - - - 源文件 - - - - - 源文件 - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + + + 源文件 + + \ No newline at end of file diff --git a/wcf/wcf.vcxproj.user b/WeChatFerry/sdk/SDK.vcxproj.user similarity index 100% rename from wcf/wcf.vcxproj.user rename to WeChatFerry/sdk/SDK.vcxproj.user diff --git a/sdk/dllmain.cpp b/WeChatFerry/sdk/dllmain.cpp similarity index 96% rename from sdk/dllmain.cpp rename to WeChatFerry/sdk/dllmain.cpp index 1d8e3d4..66475e4 100644 --- a/sdk/dllmain.cpp +++ b/WeChatFerry/sdk/dllmain.cpp @@ -1,14 +1,14 @@ -// dllmain.cpp : 定义 DLL 应用程序的入口点。 -#include "framework.h" - -BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) -{ - switch (ul_reason_for_call) { - case DLL_PROCESS_ATTACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} +// dllmain.cpp : 定义 DLL 应用程序的入口点。 +#include "framework.h" + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + switch (ul_reason_for_call) { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} diff --git a/spy/framework.h b/WeChatFerry/sdk/framework.h similarity index 96% rename from spy/framework.h rename to WeChatFerry/sdk/framework.h index 3f0fc4a..80cbbc9 100644 --- a/spy/framework.h +++ b/WeChatFerry/sdk/framework.h @@ -1,5 +1,5 @@ -#pragma once - -#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容 -// Windows 头文件 -#include +#pragma once + +#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容 +// Windows 头文件 +#include diff --git a/sdk/injector.cpp b/WeChatFerry/sdk/injector.cpp similarity index 96% rename from sdk/injector.cpp rename to WeChatFerry/sdk/injector.cpp index 3717708..bad72b9 100644 --- a/sdk/injector.cpp +++ b/WeChatFerry/sdk/injector.cpp @@ -1,122 +1,122 @@ -#include "injector.h" - -HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase) -{ - HANDLE hThread; - SIZE_T cszDLL = (wcslen(dllPath) + 1) * sizeof(WCHAR); - // 1. 打开目标进程 - HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); - if (hProcess == NULL) { - MessageBox(NULL, L"打开进程失败", L"InjectDll", 0); - return NULL; - } - - // 2. 在目标进程的内存里开辟空间 - LPVOID pRemoteAddress = VirtualAllocEx(hProcess, NULL, cszDLL, MEM_COMMIT, PAGE_READWRITE); - if (pRemoteAddress == NULL) { - MessageBox(NULL, L"DLL 路径写入失败", L"InjectDll", 0); - return NULL; - } - - // 3. 把 dll 的路径写入到目标进程的内存空间中 - WriteProcessMemory(hProcess, pRemoteAddress, dllPath, cszDLL, NULL); - - // 3. 创建一个远程线程,让目标进程调用 LoadLibrary - hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, pRemoteAddress, 0, NULL); - if (hThread == NULL) { - MessageBox(NULL, L"LoadLibrary 调用失败", L"InjectDll", 0); - return NULL; - } - - WaitForSingleObject(hThread, -1); - GetExitCodeThread(hThread, (LPDWORD)injectedBase); - CloseHandle(hThread); - VirtualFreeEx(hProcess, pRemoteAddress, 0, MEM_RELEASE); - // CloseHandle(hProcess); // Close when exit - - return hProcess; -} - -bool EjectDll(HANDLE process, HMODULE dllBase) -{ - HANDLE hThread = NULL; - - // 使目标进程调用 FreeLibrary,卸载 DLL - hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, (LPVOID)dllBase, 0, NULL); - if (hThread == NULL) { - MessageBox(NULL, L"FreeLibrary 调用失败!", L"EjectDll", 0); - return false; - } - - WaitForSingleObject(hThread, INFINITE); - CloseHandle(hThread); - CloseHandle(process); - return true; -} - -static void *GetFuncAddr(LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName) -{ - HMODULE hLoaded = LoadLibrary(dllPath); - if (hLoaded == NULL) { - return NULL; - } - - void *absAddr = GetProcAddress(hLoaded, funcName); - DWORD offset = (DWORD)absAddr - (DWORD)hLoaded; - - FreeLibrary(hLoaded); - - return (void *)((DWORD)dllBase + offset); -} - -bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, DWORD *ret) -{ - void *pFunc = GetFuncAddr(dllPath, dllBase, funcName); - if (pFunc == NULL) { - return false; - } - - HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, parameter, 0, NULL); - if (hThread == NULL) { - return false; - } - WaitForSingleObject(hThread, INFINITE); - if (ret != NULL) { - GetExitCodeThread(hThread, ret); - } - - CloseHandle(hThread); - return true; -} - -bool CallDllFuncEx(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, size_t sz, - DWORD *ret) -{ - void *pFunc = GetFuncAddr(dllPath, dllBase, funcName); - if (pFunc == NULL) { - return false; - } - - LPVOID pRemoteAddress = VirtualAllocEx(process, NULL, sz, MEM_COMMIT, PAGE_READWRITE); - if (pRemoteAddress == NULL) { - MessageBox(NULL, L"申请内存失败", L"CallDllFuncEx", 0); - return NULL; - } - - WriteProcessMemory(process, pRemoteAddress, parameter, sz, NULL); - - HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, pRemoteAddress, 0, NULL); - if (hThread == NULL) { - VirtualFree(pRemoteAddress, 0, MEM_RELEASE); - MessageBox(NULL, L"远程调用失败", L"CallDllFuncEx", 0); - return false; - } - WaitForSingleObject(hThread, INFINITE); - VirtualFree(pRemoteAddress, 0, MEM_RELEASE); - if (ret != NULL) { - GetExitCodeThread(hThread, ret); - } - - CloseHandle(hThread); - return true; -} +#include "injector.h" + +HANDLE InjectDll(DWORD pid, LPCWSTR dllPath, HMODULE *injectedBase) +{ + HANDLE hThread; + SIZE_T cszDLL = (wcslen(dllPath) + 1) * sizeof(WCHAR); + // 1. 打开目标进程 + HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); + if (hProcess == NULL) { + MessageBox(NULL, L"打开进程失败", L"InjectDll", 0); + return NULL; + } + + // 2. 在目标进程的内存里开辟空间 + LPVOID pRemoteAddress = VirtualAllocEx(hProcess, NULL, cszDLL, MEM_COMMIT, PAGE_READWRITE); + if (pRemoteAddress == NULL) { + MessageBox(NULL, L"DLL 路径写入失败", L"InjectDll", 0); + return NULL; + } + + // 3. 把 dll 的路径写入到目标进程的内存空间中 + WriteProcessMemory(hProcess, pRemoteAddress, dllPath, cszDLL, NULL); + + // 3. 创建一个远程线程,让目标进程调用 LoadLibrary + hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, pRemoteAddress, 0, NULL); + if (hThread == NULL) { + MessageBox(NULL, L"LoadLibrary 调用失败", L"InjectDll", 0); + return NULL; + } + + WaitForSingleObject(hThread, -1); + GetExitCodeThread(hThread, (LPDWORD)injectedBase); + CloseHandle(hThread); + VirtualFreeEx(hProcess, pRemoteAddress, 0, MEM_RELEASE); + // CloseHandle(hProcess); // Close when exit + + return hProcess; +} + +bool EjectDll(HANDLE process, HMODULE dllBase) +{ + HANDLE hThread = NULL; + + // 使目标进程调用 FreeLibrary,卸载 DLL + hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)FreeLibrary, (LPVOID)dllBase, 0, NULL); + if (hThread == NULL) { + MessageBox(NULL, L"FreeLibrary 调用失败!", L"EjectDll", 0); + return false; + } + + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + CloseHandle(process); + return true; +} + +static void *GetFuncAddr(LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName) +{ + HMODULE hLoaded = LoadLibrary(dllPath); + if (hLoaded == NULL) { + return NULL; + } + + void *absAddr = GetProcAddress(hLoaded, funcName); + DWORD offset = (DWORD)absAddr - (DWORD)hLoaded; + + FreeLibrary(hLoaded); + + return (void *)((DWORD)dllBase + offset); +} + +bool CallDllFunc(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, DWORD *ret) +{ + void *pFunc = GetFuncAddr(dllPath, dllBase, funcName); + if (pFunc == NULL) { + return false; + } + + HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, parameter, 0, NULL); + if (hThread == NULL) { + return false; + } + WaitForSingleObject(hThread, INFINITE); + if (ret != NULL) { + GetExitCodeThread(hThread, ret); + } + + CloseHandle(hThread); + return true; +} + +bool CallDllFuncEx(HANDLE process, LPCWSTR dllPath, HMODULE dllBase, LPCSTR funcName, LPVOID parameter, size_t sz, + DWORD *ret) +{ + void *pFunc = GetFuncAddr(dllPath, dllBase, funcName); + if (pFunc == NULL) { + return false; + } + + LPVOID pRemoteAddress = VirtualAllocEx(process, NULL, sz, MEM_COMMIT, PAGE_READWRITE); + if (pRemoteAddress == NULL) { + MessageBox(NULL, L"申请内存失败", L"CallDllFuncEx", 0); + return NULL; + } + + WriteProcessMemory(process, pRemoteAddress, parameter, sz, NULL); + + HANDLE hThread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)pFunc, pRemoteAddress, 0, NULL); + if (hThread == NULL) { + VirtualFree(pRemoteAddress, 0, MEM_RELEASE); + MessageBox(NULL, L"远程调用失败", L"CallDllFuncEx", 0); + return false; + } + WaitForSingleObject(hThread, INFINITE); + VirtualFree(pRemoteAddress, 0, MEM_RELEASE); + if (ret != NULL) { + GetExitCodeThread(hThread, ret); + } + + CloseHandle(hThread); + return true; +} diff --git a/sdk/injector.h b/WeChatFerry/sdk/injector.h similarity index 100% rename from sdk/injector.h rename to WeChatFerry/sdk/injector.h diff --git a/sdk/sdk.cpp b/WeChatFerry/sdk/sdk.cpp similarity index 96% rename from sdk/sdk.cpp rename to WeChatFerry/sdk/sdk.cpp index b720a4d..0b996bc 100644 --- a/sdk/sdk.cpp +++ b/WeChatFerry/sdk/sdk.cpp @@ -1,125 +1,125 @@ -#include "Shlwapi.h" -#include "framework.h" -#include -#include -#include - -#include "injector.h" -#include "sdk.h" -#include "util.h" - -#define WCF_LOCK ".wcf.lock" - -static bool debugMode = false; -static HANDLE wcProcess = NULL; -static HMODULE spyBase = NULL; -static WCHAR spyDllPath[MAX_PATH] = { 0 }; - -static int GetDllPath(bool debug, wchar_t *dllPath) -{ - GetModuleFileName(GetModuleHandle(WECHATSDKDLL), spyDllPath, MAX_PATH); - PathRemoveFileSpec(spyDllPath); - if (debug) { - PathAppend(spyDllPath, WECHATINJECTDLL_DEBUG); - } else { - PathAppend(spyDllPath, WECHATINJECTDLL); - } - - if (!PathFileExists(spyDllPath)) { - MessageBox(NULL, spyDllPath, L"文件不存在", 0); - return ERROR_FILE_NOT_FOUND; - } - - return 0; -} - -int WxInitSDK(bool debug, int port) -{ - int status = 0; - DWORD wcPid = 0; - - status = GetDllPath(debug, spyDllPath); - if (status != 0) { - return status; - } - - status = OpenWeChat(&wcPid); - if (status != 0) { - MessageBox(NULL, L"打开微信失败", L"WxInitSDK", 0); - return status; - } - - Sleep(2000); // 等待微信打开 - wcProcess = InjectDll(wcPid, spyDllPath, &spyBase); - if (wcProcess == NULL) { - MessageBox(NULL, L"注入失败", L"WxInitSDK", 0); - return -1; - } - - PortPath_t pp = { 0 }; - pp.port = port; - sprintf_s(pp.path, MAX_PATH, "%s", std::filesystem::current_path().string().c_str()); - - if (!CallDllFuncEx(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)&pp, sizeof(PortPath_t), NULL)) { - MessageBox(NULL, L"初始化失败", L"WxInitSDK", 0); - return -1; - } - -#ifdef WCF - FILE *fd = fopen(WCF_LOCK, "wb"); - if (fd == NULL) { - MessageBox(NULL, L"无法打开lock文件", L"WxInitSDK", 0); - return -2; - } - fwrite((uint8_t *)&debug, sizeof(debug), 1, fd); - fwrite((uint8_t *)&spyBase, sizeof(spyBase), 1, fd); - fclose(fd); -#endif - debugMode = debug; - return 0; -} - -int WxDestroySDK() -{ - int status = 0; -#ifdef WCF - bool debug; - DWORD pid = GetWeChatPid(); - if (pid == 0) { - MessageBox(NULL, L"微信未运行", L"WxDestroySDK", 0); - return status; - } - - wcProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); - if (wcProcess == NULL) { - MessageBox(NULL, L"微信未运行", L"WxDestroySDK", 0); - return -1; - } - - FILE *fd = fopen(WCF_LOCK, "rb"); - if (fd == NULL) { - MessageBox(NULL, L"无法打开lock文件", L"WxDestroySDK", 0); - return -2; - } - fread((uint8_t *)&debug, sizeof(debug), 1, fd); - fread((uint8_t *)&spyBase, sizeof(spyBase), 1, fd); - fclose(fd); - status = GetDllPath(debug, spyDllPath); -#else - status = GetDllPath(debugMode, spyDllPath); -#endif - - if (status != 0) { - return status; - } - - if (!CallDllFunc(wcProcess, spyDllPath, spyBase, "CleanupSpy", NULL, NULL)) { - return -1; - } - - if (!EjectDll(wcProcess, spyBase)) { - return -1; // TODO: Unify error codes - } - - return 0; -} +#include "Shlwapi.h" +#include "framework.h" +#include +#include +#include + +#include "injector.h" +#include "sdk.h" +#include "util.h" + +#define WCF_LOCK ".wcf.lock" + +static bool debugMode = false; +static HANDLE wcProcess = NULL; +static HMODULE spyBase = NULL; +static WCHAR spyDllPath[MAX_PATH] = { 0 }; + +static int GetDllPath(bool debug, wchar_t *dllPath) +{ + GetModuleFileName(GetModuleHandle(WECHATSDKDLL), spyDllPath, MAX_PATH); + PathRemoveFileSpec(spyDllPath); + if (debug) { + PathAppend(spyDllPath, WECHATINJECTDLL_DEBUG); + } else { + PathAppend(spyDllPath, WECHATINJECTDLL); + } + + if (!PathFileExists(spyDllPath)) { + MessageBox(NULL, spyDllPath, L"文件不存在", 0); + return ERROR_FILE_NOT_FOUND; + } + + return 0; +} + +int WxInitSDK(bool debug, int port) +{ + int status = 0; + DWORD wcPid = 0; + + status = GetDllPath(debug, spyDllPath); + if (status != 0) { + return status; + } + + status = OpenWeChat(&wcPid); + if (status != 0) { + MessageBox(NULL, L"打开微信失败", L"WxInitSDK", 0); + return status; + } + + Sleep(2000); // 等待微信打开 + wcProcess = InjectDll(wcPid, spyDllPath, &spyBase); + if (wcProcess == NULL) { + MessageBox(NULL, L"注入失败", L"WxInitSDK", 0); + return -1; + } + + PortPath_t pp = { 0 }; + pp.port = port; + sprintf_s(pp.path, MAX_PATH, "%s", std::filesystem::current_path().string().c_str()); + + if (!CallDllFuncEx(wcProcess, spyDllPath, spyBase, "InitSpy", (LPVOID)&pp, sizeof(PortPath_t), NULL)) { + MessageBox(NULL, L"初始化失败", L"WxInitSDK", 0); + return -1; + } + +#ifdef WCF + FILE *fd = fopen(WCF_LOCK, "wb"); + if (fd == NULL) { + MessageBox(NULL, L"无法打开lock文件", L"WxInitSDK", 0); + return -2; + } + fwrite((uint8_t *)&debug, sizeof(debug), 1, fd); + fwrite((uint8_t *)&spyBase, sizeof(spyBase), 1, fd); + fclose(fd); +#endif + debugMode = debug; + return 0; +} + +int WxDestroySDK() +{ + int status = 0; +#ifdef WCF + bool debug; + DWORD pid = GetWeChatPid(); + if (pid == 0) { + MessageBox(NULL, L"微信未运行", L"WxDestroySDK", 0); + return status; + } + + wcProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); + if (wcProcess == NULL) { + MessageBox(NULL, L"微信未运行", L"WxDestroySDK", 0); + return -1; + } + + FILE *fd = fopen(WCF_LOCK, "rb"); + if (fd == NULL) { + MessageBox(NULL, L"无法打开lock文件", L"WxDestroySDK", 0); + return -2; + } + fread((uint8_t *)&debug, sizeof(debug), 1, fd); + fread((uint8_t *)&spyBase, sizeof(spyBase), 1, fd); + fclose(fd); + status = GetDllPath(debug, spyDllPath); +#else + status = GetDllPath(debugMode, spyDllPath); +#endif + + if (status != 0) { + return status; + } + + if (!CallDllFunc(wcProcess, spyDllPath, spyBase, "CleanupSpy", NULL, NULL)) { + return -1; + } + + if (!EjectDll(wcProcess, spyBase)) { + return -1; // TODO: Unify error codes + } + + return 0; +} diff --git a/sdk/sdk.def b/WeChatFerry/sdk/sdk.def similarity index 93% rename from sdk/sdk.def rename to WeChatFerry/sdk/sdk.def index e601ae1..d8c9be9 100644 --- a/sdk/sdk.def +++ b/WeChatFerry/sdk/sdk.def @@ -1,3 +1,3 @@ -EXPORTS - WxInitSDK - WxDestroySDK +EXPORTS + WxInitSDK + WxDestroySDK diff --git a/sdk/sdk.h b/WeChatFerry/sdk/sdk.h similarity index 94% rename from sdk/sdk.h rename to WeChatFerry/sdk/sdk.h index 68f4ccf..0ebec29 100644 --- a/sdk/sdk.h +++ b/WeChatFerry/sdk/sdk.h @@ -1,4 +1,4 @@ -#pragma once - -int WxInitSDK(bool debug, int port); -int WxDestroySDK(); +#pragma once + +int WxInitSDK(bool debug, int port); +int WxDestroySDK(); diff --git a/spy/Spy.vcxproj b/WeChatFerry/spy/Spy.vcxproj similarity index 96% rename from spy/Spy.vcxproj rename to WeChatFerry/spy/Spy.vcxproj index 2c78b33..e28f3f9 100644 --- a/spy/Spy.vcxproj +++ b/WeChatFerry/spy/Spy.vcxproj @@ -1,278 +1,278 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {4de80b82-5f6a-4c4c-9d16-1574308110fa} - spy - 10.0 - x86-windows-static - x64-windows-static - - - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - true - Unicode - - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - $(ProjectName)_debug - true - - - false - true - - - true - - - false - - - true - - - true - Release - - - - Level3 - true - true - true - WIN32;NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;ENABLE_DEBUG_LOG;%(PreprocessorDefinitions) - true - NotUsing - - - $(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include - - 4251;4731;4819 - MultiThreaded - stdcpp17 - /EHa %(AdditionalOptions) - - - Windows - true - true - true - false - iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies) - spy.def - - - if not exist $(SolutionDir)Out md $(SolutionDir)Out -xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out -xcopy /y $(OutDir)$(TargetName).exp $(SolutionDir)Out -xcopy /y $(OutDir)$(TargetName).lib $(SolutionDir)Out -xcopy /y $(OutDir)$(TargetName).pdb $(SolutionDir)Out -xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)python\wcferry - - - Copy spy.dll - - - cd $(SolutionDir)rpc\proto -$(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto - - - Generating PB files - - - - - Level3 - true - true - true - WIN32;NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - NotUsing - - - $(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include - - 4251;4731;4819 - MultiThreaded - stdcpp17 - - - Windows - true - true - true - false - iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies) - spy.def - - - if not exist $(SolutionDir)Out md $(SolutionDir)Out -xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out -xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)python\wcferry - - - Copy spy.dll - - - cd $(SolutionDir)rpc\proto -$(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto - - - Generating PB files - - - - - Level3 - true - _DEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - pch.h - - - Windows - true - false - spy.def - - - - - Level3 - true - true - true - NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - pch.h - - - Windows - true - true - true - false - spy.def - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {4de80b82-5f6a-4c4c-9d16-1574308110fa} + spy + 10.0 + x86-windows-static + x64-windows-static + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(ProjectName)_debug + true + + + false + true + + + true + + + false + + + true + + + true + Release + + + + Level3 + true + true + true + WIN32;NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;ENABLE_DEBUG_LOG;%(PreprocessorDefinitions) + true + NotUsing + + + $(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include + + 4251;4731;4819 + MultiThreaded + stdcpp17 + /EHa %(AdditionalOptions) + + + Windows + true + true + true + false + iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies) + spy.def + + + if not exist $(SolutionDir)Out md $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetName).exp $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetName).lib $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetName).pdb $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry + + + Copy spy.dll + + + cd $(SolutionDir)rpc\proto +$(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto + + + Generating PB files + + + + + Level3 + true + true + true + WIN32;NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + + + $(SolutionDir)rpc;$(SolutionDir)rpc\nanopb;$(SolutionDir)rpc\proto;$(SolutionDir)spy;C:\Tools\vcpkg\installed\x86-windows-static\include + + 4251;4731;4819 + MultiThreaded + stdcpp17 + + + Windows + true + true + true + false + iphlpapi.lib;wsock32.lib;ws2_32.lib;crypt32.lib;%(AdditionalDependencies) + spy.def + + + if not exist $(SolutionDir)Out md $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out +xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry + + + Copy spy.dll + + + cd $(SolutionDir)rpc\proto +$(SolutionDir)rpc\tool\protoc --nanopb_out=. wcf.proto + + + Generating PB files + + + + + Level3 + true + _DEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + spy.def + + + + + Level3 + true + true + true + NDEBUG;SPY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + true + true + false + spy.def + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spy/Spy.vcxproj.filters b/WeChatFerry/spy/Spy.vcxproj.filters similarity index 96% rename from spy/Spy.vcxproj.filters rename to WeChatFerry/spy/Spy.vcxproj.filters index a7ce58b..64edd64 100644 --- a/spy/Spy.vcxproj.filters +++ b/WeChatFerry/spy/Spy.vcxproj.filters @@ -1,166 +1,166 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - {7e39c2cc-c605-4204-88dc-9ae15c7d8d6c} - - - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - nnrpc - - - nnrpc - - - nnrpc - - - nnrpc - - - nnrpc - - - nnrpc - - - nnrpc - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - 头文件 - - - - - 源文件 - - - 源文件 - - - 源文件 - - - 源文件 - - - 源文件 - - - 源文件 - - - 源文件 - - - 源文件 - - - 源文件 - - - 源文件 - - - nnrpc - - - nnrpc - - - nnrpc - - - nnrpc - - - nnrpc - - - 源文件 - - - 源文件 - - - 源文件 - - - 源文件 - - - - - 源文件 - - - nnrpc - - - - - 资源文件 - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {7e39c2cc-c605-4204-88dc-9ae15c7d8d6c} + + + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + nnrpc + + + nnrpc + + + nnrpc + + + nnrpc + + + nnrpc + + + nnrpc + + + nnrpc + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + 头文件 + + + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + nnrpc + + + nnrpc + + + nnrpc + + + nnrpc + + + nnrpc + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + + + 源文件 + + + nnrpc + + + + + 资源文件 + + \ No newline at end of file diff --git a/spy/Spy.vcxproj.user b/WeChatFerry/spy/Spy.vcxproj.user similarity index 92% rename from spy/Spy.vcxproj.user rename to WeChatFerry/spy/Spy.vcxproj.user index 0f14913..88a5509 100644 --- a/spy/Spy.vcxproj.user +++ b/WeChatFerry/spy/Spy.vcxproj.user @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/spy/chatroom_mgmt.cpp b/WeChatFerry/spy/chatroom_mgmt.cpp similarity index 100% rename from spy/chatroom_mgmt.cpp rename to WeChatFerry/spy/chatroom_mgmt.cpp diff --git a/spy/chatroom_mgmt.h b/WeChatFerry/spy/chatroom_mgmt.h similarity index 100% rename from spy/chatroom_mgmt.h rename to WeChatFerry/spy/chatroom_mgmt.h diff --git a/spy/contact_mgmt.cpp b/WeChatFerry/spy/contact_mgmt.cpp similarity index 100% rename from spy/contact_mgmt.cpp rename to WeChatFerry/spy/contact_mgmt.cpp diff --git a/spy/contact_mgmt.h b/WeChatFerry/spy/contact_mgmt.h similarity index 100% rename from spy/contact_mgmt.h rename to WeChatFerry/spy/contact_mgmt.h diff --git a/spy/decrypt_image.cpp b/WeChatFerry/spy/decrypt_image.cpp similarity index 100% rename from spy/decrypt_image.cpp rename to WeChatFerry/spy/decrypt_image.cpp diff --git a/spy/decrypt_image.h b/WeChatFerry/spy/decrypt_image.h similarity index 100% rename from spy/decrypt_image.h rename to WeChatFerry/spy/decrypt_image.h diff --git a/spy/dllmain.cpp b/WeChatFerry/spy/dllmain.cpp similarity index 100% rename from spy/dllmain.cpp rename to WeChatFerry/spy/dllmain.cpp diff --git a/spy/exec_sql.cpp b/WeChatFerry/spy/exec_sql.cpp similarity index 100% rename from spy/exec_sql.cpp rename to WeChatFerry/spy/exec_sql.cpp diff --git a/spy/exec_sql.h b/WeChatFerry/spy/exec_sql.h similarity index 100% rename from spy/exec_sql.h rename to WeChatFerry/spy/exec_sql.h diff --git a/sdk/framework.h b/WeChatFerry/spy/framework.h similarity index 96% rename from sdk/framework.h rename to WeChatFerry/spy/framework.h index 3f0fc4a..80cbbc9 100644 --- a/sdk/framework.h +++ b/WeChatFerry/spy/framework.h @@ -1,5 +1,5 @@ -#pragma once - -#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容 -// Windows 头文件 -#include +#pragma once + +#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容 +// Windows 头文件 +#include diff --git a/spy/load_calls.cpp b/WeChatFerry/spy/load_calls.cpp similarity index 97% rename from spy/load_calls.cpp rename to WeChatFerry/spy/load_calls.cpp index eb88af6..9384492 100644 --- a/spy/load_calls.cpp +++ b/WeChatFerry/spy/load_calls.cpp @@ -1,39 +1,39 @@ -#include -#include - -#include "load_calls.h" - -#define SUPPORT_VERSION L"3.9.2.23" -WxCalls_t wxCalls = { - 0x2FFD638, // Login Status - { 0x2FFD484, 0x2FFD590, 0x2FFD500, 0x30238CC }, // User Info: wxid, nickname, mobile, home - { 0x768140, 0xCE6C80, 0x756960 }, // Send Message - /* Receive Message: - Hook, call, type, self, id, msgXml, roomId, wxId, content, thumb, extra */ - { 0xD19A0B, 0x756960, 0x38, 0x3C, 0x194, 0x1FC, 0x48, 0x180, 0x70, 0x1A8, 0x1BC }, - { 0x768140, 0XF59E40, 0XCE6640, 0x756960 }, // Send Image Message - { 0x76AE20, 0xF59E40, 0xB6D1F0, 0x756960 }, // Send File Message - { 0xB8A70, 0x3ED5E0, 0x107F00, 0x3ED7B0, 0x2386FE4 }, // Send xml Message - { 0x771980, 0x4777E0, 0x239E888 }, // Send Emotion Message - /* Get Contacts: - call1, call2, wxId, Code, Remark,Name, Gender, Country, Province, City*/ - { 0x75A4A0, 0xC089F0, 0x10, 0x24, 0x58, 0x6C, 0x0E, 0x00, 0x00, 0x00 }, - /* Exec Sql: - Exec, base, start, end, slot, name*/ - { 0x141BDF0, 0x2366934, 0x1428, 0x142C, 0x3C, 0x50 }, - { 0xA17D50, 0xF59E40, 0xA18BD0, 0xA17E70 }, // Accept New Friend application - { 0x78CF20, 0xF59E40, 0xBD1DC0 }, // Add chatroom members - { 0x78CF20, 0xF59E40, 0xBD22A0 }, // Delete chatroom members - { 0x7B2E60, 0x15E2C20, 0x79C250 } // Receive transfer -}; - -int LoadCalls(const wchar_t *version, WxCalls_t *calls) -{ - if (wcscmp(version, SUPPORT_VERSION) != 0) { - return -1; - } - - memcpy_s(calls, sizeof(WxCalls_t), &wxCalls, sizeof(WxCalls_t)); - - return 0; -} +#include +#include + +#include "load_calls.h" + +#define SUPPORT_VERSION L"3.9.2.23" +WxCalls_t wxCalls = { + 0x2FFD638, // Login Status + { 0x2FFD484, 0x2FFD590, 0x2FFD500, 0x30238CC }, // User Info: wxid, nickname, mobile, home + { 0x768140, 0xCE6C80, 0x756960 }, // Send Message + /* Receive Message: + Hook, call, type, self, id, msgXml, roomId, wxId, content, thumb, extra */ + { 0xD19A0B, 0x756960, 0x38, 0x3C, 0x194, 0x1FC, 0x48, 0x180, 0x70, 0x1A8, 0x1BC }, + { 0x768140, 0XF59E40, 0XCE6640, 0x756960 }, // Send Image Message + { 0x76AE20, 0xF59E40, 0xB6D1F0, 0x756960 }, // Send File Message + { 0xB8A70, 0x3ED5E0, 0x107F00, 0x3ED7B0, 0x2386FE4 }, // Send xml Message + { 0x771980, 0x4777E0, 0x239E888 }, // Send Emotion Message + /* Get Contacts: + call1, call2, wxId, Code, Remark,Name, Gender, Country, Province, City*/ + { 0x75A4A0, 0xC089F0, 0x10, 0x24, 0x58, 0x6C, 0x0E, 0x00, 0x00, 0x00 }, + /* Exec Sql: + Exec, base, start, end, slot, name*/ + { 0x141BDF0, 0x2366934, 0x1428, 0x142C, 0x3C, 0x50 }, + { 0xA17D50, 0xF59E40, 0xA18BD0, 0xA17E70 }, // Accept New Friend application + { 0x78CF20, 0xF59E40, 0xBD1DC0 }, // Add chatroom members + { 0x78CF20, 0xF59E40, 0xBD22A0 }, // Delete chatroom members + { 0x7B2E60, 0x15E2C20, 0x79C250 } // Receive transfer +}; + +int LoadCalls(const wchar_t *version, WxCalls_t *calls) +{ + if (wcscmp(version, SUPPORT_VERSION) != 0) { + return -1; + } + + memcpy_s(calls, sizeof(WxCalls_t), &wxCalls, sizeof(WxCalls_t)); + + return 0; +} diff --git a/spy/load_calls.h b/WeChatFerry/spy/load_calls.h similarity index 95% rename from spy/load_calls.h rename to WeChatFerry/spy/load_calls.h index e95dae0..2f8410e 100644 --- a/spy/load_calls.h +++ b/WeChatFerry/spy/load_calls.h @@ -1,5 +1,5 @@ -#pragma once - -#include "spy_types.h" - -int LoadCalls(const wchar_t *version, WxCalls_t *calls); +#pragma once + +#include "spy_types.h" + +int LoadCalls(const wchar_t *version, WxCalls_t *calls); diff --git a/spy/log.cpp b/WeChatFerry/spy/log.cpp similarity index 100% rename from spy/log.cpp rename to WeChatFerry/spy/log.cpp diff --git a/spy/log.h b/WeChatFerry/spy/log.h similarity index 100% rename from spy/log.h rename to WeChatFerry/spy/log.h diff --git a/spy/receive_msg.cpp b/WeChatFerry/spy/receive_msg.cpp similarity index 96% rename from spy/receive_msg.cpp rename to WeChatFerry/spy/receive_msg.cpp index 6be0b1e..e495a63 100644 --- a/spy/receive_msg.cpp +++ b/WeChatFerry/spy/receive_msg.cpp @@ -1,175 +1,175 @@ -#pragma execution_character_set("utf-8") - -#include "framework.h" -#include -#include -#include - -#include "load_calls.h" -#include "receive_msg.h" -#include "user_info.h" -#include "util.h" - -// Defined in rpc_server.cpp -extern bool gIsListening; -extern mutex gMutex; -extern condition_variable gCV; -extern queue gMsgQueue; - -// Defined in spy.cpp -extern WxCalls_t g_WxCalls; -extern DWORD g_WeChatWinDllAddr; - -static DWORD reg_buffer = 0; -static DWORD recvMsgHookAddr = 0; -static DWORD recvMsgCallAddr = 0; -static DWORD recvMsgJumpBackAddr = 0; -static CHAR recvMsgBackupCode[5] = { 0 }; - -MsgTypes_t GetMsgTypes() -{ - const MsgTypes_t m = { - { 0x01, "文字" }, - { 0x03, "图片" }, - { 0x22, "语音" }, - { 0x25, "好友确认" }, - { 0x28, "POSSIBLEFRIEND_MSG" }, - { 0x2A, "名片" }, - { 0x2B, "视频" }, - { 0x2F, "石头剪刀布 | 表情图片" }, - { 0x30, "位置" }, - { 0x31, "共享实时位置、文件、转账、链接" }, - { 0x32, "VOIPMSG" }, - { 0x33, "微信初始化" }, - { 0x34, "VOIPNOTIFY" }, - { 0x35, "VOIPINVITE" }, - { 0x3E, "小视频" }, - { 0x42, "微信红包" }, - { 0x270F, "SYSNOTICE" }, - { 0x2710, "红包、系统消息" }, - { 0x2712, "撤回消息" }, - { 0x100031, "搜狗表情" }, - { 0x1000031, "链接" }, - { 0x1A000031, "微信红包" }, - { 0x20010031, "红包封面" }, - { 0x2D000031, "视频号视频" }, - { 0x2E000031, "视频号名片" }, - { 0x31000031, "引用消息" }, - { 0x37000031, "拍一拍" }, - { 0x3A000031, "视频号直播" }, - { 0x3A100031, "商品链接" }, - { 0x3A200031, "视频号直播" }, - { 0x3E000031, "音乐链接" }, - { 0x41000031, "文件" }, - }; - - return m; -} - -void HookAddress(DWORD hookAddr, LPVOID funcAddr, CHAR recvMsgBackupCode[5]) -{ - // 组装跳转数据 - BYTE jmpCode[5] = { 0 }; - jmpCode[0] = 0xE9; - - // 计算偏移 - *(DWORD *)&jmpCode[1] = (DWORD)funcAddr - hookAddr - 5; - - // 备份原来的代码 - ReadProcessMemory(GetCurrentProcess(), (LPVOID)hookAddr, recvMsgBackupCode, 5, 0); - // 写入新的代码 - WriteProcessMemory(GetCurrentProcess(), (LPVOID)hookAddr, jmpCode, 5, 0); -} - -void UnHookAddress(DWORD hookAddr, CHAR restoreCode[5]) -{ - WriteProcessMemory(GetCurrentProcess(), (LPVOID)hookAddr, restoreCode, 5, 0); -} - -void DispatchMsg(DWORD reg) -{ - WxMsg_t wxMsg; - - wxMsg.type = GET_DWORD(reg + g_WxCalls.recvMsg.type); - wxMsg.is_self = GET_DWORD(reg + g_WxCalls.recvMsg.isSelf); - wxMsg.id = GetStringByStrAddr(reg + g_WxCalls.recvMsg.msgId); - wxMsg.xml = GetStringByStrAddr(reg + g_WxCalls.recvMsg.msgXml); - - string roomid = GetStringByWstrAddr(reg + g_WxCalls.recvMsg.roomId); - if (roomid.find("@chatroom") != string::npos) { // 群 ID 的格式为 xxxxxxxxxxx@chatroom - wxMsg.is_group = true; - wxMsg.roomid = roomid; - if (wxMsg.is_self) { - wxMsg.sender = GetSelfWxid(); - } else { - wxMsg.sender = GetStringByStrAddr(reg + g_WxCalls.recvMsg.wxId); - } - } else { - wxMsg.is_group = false; - if (wxMsg.is_self) { - wxMsg.sender = GetSelfWxid(); - } else { - wxMsg.sender = roomid; - } - } - - wxMsg.content = GetStringByWstrAddr(reg + g_WxCalls.recvMsg.content); - - wxMsg.thumb = GetStringByStrAddr(reg + g_WxCalls.recvMsg.thumb); - if (!wxMsg.thumb.empty()) { - wxMsg.thumb = GetHomePath() + wxMsg.thumb; - } - - wxMsg.extra = GetStringByStrAddr(reg + g_WxCalls.recvMsg.extra); - if (!wxMsg.extra.empty()) { - wxMsg.extra = GetHomePath() + wxMsg.extra; - } - - { - unique_lock lock(gMutex); - gMsgQueue.push(wxMsg); // 推送到队列 - } - - gCV.notify_all(); // 通知各方消息就绪 -} - -__declspec(naked) void RecieveMsgFunc() -{ - __asm { - pushad - pushfd - push ecx - call DispatchMsg - add esp, 0x4 - popfd - popad - call recvMsgCallAddr // 这个为被覆盖的call - jmp recvMsgJumpBackAddr // 跳回被HOOK指令的下一条指令 - } -} - -void ListenMessage() -{ - // DbgMsg("ListenMessage"); - // OutputDebugString(L"ListenMessage\n"); - // MessageBox(NULL, L"ListenMessage", L"ListenMessage", 0); - if (gIsListening || (g_WeChatWinDllAddr == 0)) { - return; - } - - recvMsgHookAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.hook; - recvMsgCallAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.call; - recvMsgJumpBackAddr = recvMsgHookAddr + 5; - - HookAddress(recvMsgHookAddr, RecieveMsgFunc, recvMsgBackupCode); - gIsListening = true; -} - -void UnListenMessage() -{ - if (!gIsListening) { - return; - } - UnHookAddress(recvMsgHookAddr, recvMsgBackupCode); - gIsListening = false; -} +#pragma execution_character_set("utf-8") + +#include "framework.h" +#include +#include +#include + +#include "load_calls.h" +#include "receive_msg.h" +#include "user_info.h" +#include "util.h" + +// Defined in rpc_server.cpp +extern bool gIsListening; +extern mutex gMutex; +extern condition_variable gCV; +extern queue gMsgQueue; + +// Defined in spy.cpp +extern WxCalls_t g_WxCalls; +extern DWORD g_WeChatWinDllAddr; + +static DWORD reg_buffer = 0; +static DWORD recvMsgHookAddr = 0; +static DWORD recvMsgCallAddr = 0; +static DWORD recvMsgJumpBackAddr = 0; +static CHAR recvMsgBackupCode[5] = { 0 }; + +MsgTypes_t GetMsgTypes() +{ + const MsgTypes_t m = { + { 0x01, "文字" }, + { 0x03, "图片" }, + { 0x22, "语音" }, + { 0x25, "好友确认" }, + { 0x28, "POSSIBLEFRIEND_MSG" }, + { 0x2A, "名片" }, + { 0x2B, "视频" }, + { 0x2F, "石头剪刀布 | 表情图片" }, + { 0x30, "位置" }, + { 0x31, "共享实时位置、文件、转账、链接" }, + { 0x32, "VOIPMSG" }, + { 0x33, "微信初始化" }, + { 0x34, "VOIPNOTIFY" }, + { 0x35, "VOIPINVITE" }, + { 0x3E, "小视频" }, + { 0x42, "微信红包" }, + { 0x270F, "SYSNOTICE" }, + { 0x2710, "红包、系统消息" }, + { 0x2712, "撤回消息" }, + { 0x100031, "搜狗表情" }, + { 0x1000031, "链接" }, + { 0x1A000031, "微信红包" }, + { 0x20010031, "红包封面" }, + { 0x2D000031, "视频号视频" }, + { 0x2E000031, "视频号名片" }, + { 0x31000031, "引用消息" }, + { 0x37000031, "拍一拍" }, + { 0x3A000031, "视频号直播" }, + { 0x3A100031, "商品链接" }, + { 0x3A200031, "视频号直播" }, + { 0x3E000031, "音乐链接" }, + { 0x41000031, "文件" }, + }; + + return m; +} + +void HookAddress(DWORD hookAddr, LPVOID funcAddr, CHAR recvMsgBackupCode[5]) +{ + // 组装跳转数据 + BYTE jmpCode[5] = { 0 }; + jmpCode[0] = 0xE9; + + // 计算偏移 + *(DWORD *)&jmpCode[1] = (DWORD)funcAddr - hookAddr - 5; + + // 备份原来的代码 + ReadProcessMemory(GetCurrentProcess(), (LPVOID)hookAddr, recvMsgBackupCode, 5, 0); + // 写入新的代码 + WriteProcessMemory(GetCurrentProcess(), (LPVOID)hookAddr, jmpCode, 5, 0); +} + +void UnHookAddress(DWORD hookAddr, CHAR restoreCode[5]) +{ + WriteProcessMemory(GetCurrentProcess(), (LPVOID)hookAddr, restoreCode, 5, 0); +} + +void DispatchMsg(DWORD reg) +{ + WxMsg_t wxMsg; + + wxMsg.type = GET_DWORD(reg + g_WxCalls.recvMsg.type); + wxMsg.is_self = GET_DWORD(reg + g_WxCalls.recvMsg.isSelf); + wxMsg.id = GetStringByStrAddr(reg + g_WxCalls.recvMsg.msgId); + wxMsg.xml = GetStringByStrAddr(reg + g_WxCalls.recvMsg.msgXml); + + string roomid = GetStringByWstrAddr(reg + g_WxCalls.recvMsg.roomId); + if (roomid.find("@chatroom") != string::npos) { // 群 ID 的格式为 xxxxxxxxxxx@chatroom + wxMsg.is_group = true; + wxMsg.roomid = roomid; + if (wxMsg.is_self) { + wxMsg.sender = GetSelfWxid(); + } else { + wxMsg.sender = GetStringByStrAddr(reg + g_WxCalls.recvMsg.wxId); + } + } else { + wxMsg.is_group = false; + if (wxMsg.is_self) { + wxMsg.sender = GetSelfWxid(); + } else { + wxMsg.sender = roomid; + } + } + + wxMsg.content = GetStringByWstrAddr(reg + g_WxCalls.recvMsg.content); + + wxMsg.thumb = GetStringByStrAddr(reg + g_WxCalls.recvMsg.thumb); + if (!wxMsg.thumb.empty()) { + wxMsg.thumb = GetHomePath() + wxMsg.thumb; + } + + wxMsg.extra = GetStringByStrAddr(reg + g_WxCalls.recvMsg.extra); + if (!wxMsg.extra.empty()) { + wxMsg.extra = GetHomePath() + wxMsg.extra; + } + + { + unique_lock lock(gMutex); + gMsgQueue.push(wxMsg); // 推送到队列 + } + + gCV.notify_all(); // 通知各方消息就绪 +} + +__declspec(naked) void RecieveMsgFunc() +{ + __asm { + pushad + pushfd + push ecx + call DispatchMsg + add esp, 0x4 + popfd + popad + call recvMsgCallAddr // 这个为被覆盖的call + jmp recvMsgJumpBackAddr // 跳回被HOOK指令的下一条指令 + } +} + +void ListenMessage() +{ + // DbgMsg("ListenMessage"); + // OutputDebugString(L"ListenMessage\n"); + // MessageBox(NULL, L"ListenMessage", L"ListenMessage", 0); + if (gIsListening || (g_WeChatWinDllAddr == 0)) { + return; + } + + recvMsgHookAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.hook; + recvMsgCallAddr = g_WeChatWinDllAddr + g_WxCalls.recvMsg.call; + recvMsgJumpBackAddr = recvMsgHookAddr + 5; + + HookAddress(recvMsgHookAddr, RecieveMsgFunc, recvMsgBackupCode); + gIsListening = true; +} + +void UnListenMessage() +{ + if (!gIsListening) { + return; + } + UnHookAddress(recvMsgHookAddr, recvMsgBackupCode); + gIsListening = false; +} diff --git a/spy/receive_msg.h b/WeChatFerry/spy/receive_msg.h similarity index 100% rename from spy/receive_msg.h rename to WeChatFerry/spy/receive_msg.h diff --git a/spy/receive_transfer.cpp b/WeChatFerry/spy/receive_transfer.cpp similarity index 100% rename from spy/receive_transfer.cpp rename to WeChatFerry/spy/receive_transfer.cpp diff --git a/spy/receive_transfer.h b/WeChatFerry/spy/receive_transfer.h similarity index 100% rename from spy/receive_transfer.h rename to WeChatFerry/spy/receive_transfer.h diff --git a/spy/resource.h b/WeChatFerry/spy/resource.h similarity index 100% rename from spy/resource.h rename to WeChatFerry/spy/resource.h diff --git a/spy/rpc_server.cpp b/WeChatFerry/spy/rpc_server.cpp similarity index 96% rename from spy/rpc_server.cpp rename to WeChatFerry/spy/rpc_server.cpp index bbc56a6..09de304 100644 --- a/spy/rpc_server.cpp +++ b/WeChatFerry/spy/rpc_server.cpp @@ -1,759 +1,759 @@ -#pragma warning(disable : 4251) - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "wcf.pb.h" - -#include "chatroom_mgmt.h" -#include "contact_mgmt.h" -#include "decrypt_image.h" -#include "exec_sql.h" -#include "log.h" -#include "pb_types.h" -#include "pb_util.h" -#include "receive_msg.h" -#include "receive_transfer.h" -#include "rpc_server.h" -#include "send_msg.h" -#include "spy.h" -#include "spy_types.h" -#include "user_info.h" -#include "util.h" - -#define URL_SIZE 20 -#define BASE_URL "tcp://0.0.0.0" -#define G_BUF_SIZE (16 * 1024 * 1024) - -extern int IsLogin(void); // Defined in spy.cpp - -bool gIsListening; -mutex gMutex; -condition_variable gCV; -queue gMsgQueue; - -static int lport = 0; -static DWORD lThreadId = 0; -static bool lIsRunning = false; -static nng_socket sock; -static uint8_t gBuffer[G_BUF_SIZE] = { 0 }; - -bool func_is_login(uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_IS_LOGIN; - rsp.which_msg = Response_status_tag; - rsp.msg.status = IsLogin(); - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_get_self_wxid(uint8_t *out, size_t *len) -{ - string wxid = GetSelfWxid(); - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_SELF_WXID; - rsp.which_msg = Response_str_tag; - rsp.msg.str = (char *)wxid.c_str(); - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_get_msg_types(uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_MSG_TYPES; - rsp.which_msg = Response_types_tag; - - MsgTypes_t types = GetMsgTypes(); - rsp.msg.types.types.funcs.encode = encode_types; - rsp.msg.types.types.arg = &types; - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_get_contacts(uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_CONTACTS; - rsp.which_msg = Response_contacts_tag; - - vector contacts = GetContacts(); - rsp.msg.contacts.contacts.funcs.encode = encode_contacts; - rsp.msg.contacts.contacts.arg = &contacts; - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_get_db_names(uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_DB_NAMES; - rsp.which_msg = Response_dbs_tag; - - DbNames_t dbnames = GetDbNames(); - rsp.msg.dbs.names.funcs.encode = encode_dbnames; - rsp.msg.dbs.names.arg = &dbnames; - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_get_db_tables(char *db, uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_DB_TABLES; - rsp.which_msg = Response_tables_tag; - - DbTables_t tables = GetDbTables(db); - rsp.msg.tables.tables.funcs.encode = encode_tables; - rsp.msg.tables.tables.arg = &tables; - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_get_user_info(uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_USER_INFO; - rsp.which_msg = Response_ui_tag; - - UserInfo_t ui = GetUserInfo(); - rsp.msg.ui.wxid = (char *)ui.wxid.c_str(); - rsp.msg.ui.name = (char *)ui.name.c_str(); - rsp.msg.ui.mobile = (char *)ui.mobile.c_str(); - rsp.msg.ui.home = (char *)ui.home.c_str(); - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_send_txt(TextMsg txt, uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_SEND_TXT; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - if ((txt.msg == NULL) || (txt.receiver == NULL)) { - rsp.msg.status = -1; // Empty message or empty receiver - } else { - string msg(txt.msg); - string receiver(txt.receiver); - string aters(txt.aters ? txt.aters : ""); - - SendTextMessage(receiver, msg, aters); - } - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_send_img(char *path, char *receiver, uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_SEND_IMG; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - if ((path == NULL) || (receiver == NULL)) { - rsp.msg.status = -1; - } else { - SendImageMessage(receiver, path); - } - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_send_file(char *path, char *receiver, uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_SEND_IMG; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - if ((path == NULL) || (receiver == NULL)) { - rsp.msg.status = -1; - } else { - SendImageMessage(receiver, path); - } - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_send_xml(XmlMsg xml, uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_SEND_XML; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - if ((xml.content == NULL) || (xml.receiver == NULL)) { - rsp.msg.status = -1; - } else { - string receiver(xml.receiver); - string content(xml.content); - string path(xml.path ? xml.path : ""); - uint32_t type = (uint32_t)xml.type; - SendXmlMessage(receiver, content, path, type); - } - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_send_emotion(char *path, char *receiver, uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_SEND_EMOTION; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - if ((path == NULL) || (receiver == NULL)) { - rsp.msg.status = -1; - } else { - SendEmotionMessage(receiver, path); - } - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -static void PushMessage() -{ - static nng_socket msg_sock; - static uint8_t buffer[G_BUF_SIZE] = { 0 }; - - int rv; - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_ENABLE_RECV_TXT; - rsp.which_msg = Response_wxmsg_tag; - - pb_ostream_t stream = pb_ostream_from_buffer(buffer, G_BUF_SIZE); - - char url[URL_SIZE + 1] = { 0 }; - sprintf_s(url, URL_SIZE, "%s:%d", BASE_URL, lport + 1); - LOG_ERROR("URL: {}", url); - if ((rv = nng_pair1_open(&msg_sock)) != 0) { - LOG_ERROR("nng_pair0_open error {}", nng_strerror(rv)); - return; - } - - if ((rv = nng_listen(msg_sock, url, NULL, 0)) != 0) { - LOG_ERROR("nng_listen error {}", nng_strerror(rv)); - return; - } - - LOG_INFO("MSG Server listening on {}", url); - if ((rv = nng_setopt_ms(msg_sock, NNG_OPT_SENDTIMEO, 2000)) != 0) { - LOG_ERROR("nng_setopt_ms: {}", nng_strerror(rv)); - return; - } - - while (gIsListening) { - unique_lock lock(gMutex); - if (gCV.wait_for(lock, chrono::milliseconds(1000), []() { return !gMsgQueue.empty(); })) { - while (!gMsgQueue.empty()) { - auto wxmsg = gMsgQueue.front(); - rsp.msg.wxmsg.is_self = wxmsg.is_self; - rsp.msg.wxmsg.is_group = wxmsg.is_group; - rsp.msg.wxmsg.type = wxmsg.type; - rsp.msg.wxmsg.id = (char *)wxmsg.id.c_str(); - rsp.msg.wxmsg.xml = (char *)wxmsg.xml.c_str(); - rsp.msg.wxmsg.sender = (char *)wxmsg.sender.c_str(); - rsp.msg.wxmsg.roomid = (char *)wxmsg.roomid.c_str(); - rsp.msg.wxmsg.content = (char *)wxmsg.content.c_str(); - rsp.msg.wxmsg.thumb = (char *)wxmsg.thumb.c_str(); - rsp.msg.wxmsg.extra = (char *)wxmsg.extra.c_str(); - gMsgQueue.pop(); - LOG_DEBUG("Recv msg: {}", wxmsg.content); - pb_ostream_t stream = pb_ostream_from_buffer(buffer, G_BUF_SIZE); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - continue; - } - - rv = nng_send(msg_sock, buffer, stream.bytes_written, 0); - if (rv != 0) { - LOG_ERROR("nng_send: {}", nng_strerror(rv)); - } - LOG_DEBUG("Send data length {}", stream.bytes_written); - } - } - } - nng_close(msg_sock); -} - -bool func_enable_recv_txt(uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_ENABLE_RECV_TXT; - rsp.which_msg = Response_status_tag; - rsp.msg.status = -1; - - ListenMessage(); - HANDLE msgThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PushMessage, NULL, NULL, NULL); - if (msgThread != 0) { - CloseHandle(msgThread); - rsp.msg.status = 0; - } - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_disable_recv_txt(uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_DISABLE_RECV_TXT; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - UnListenMessage(); // 可能需要1秒之后才能退出,见 PushMessage - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_exec_db_query(char *db, char *sql, uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_GET_DB_TABLES; - rsp.which_msg = Response_rows_tag; - - DbRows_t rows = ExecDbQuery(db, sql); - rsp.msg.rows.rows.arg = &rows; - rsp.msg.rows.rows.funcs.encode = encode_rows; - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_SEND_IMG; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - if ((v3 == NULL) || (v4 == NULL)) { - rsp.msg.status = -1; - LOG_ERROR("Empty V3 or V4."); - } else { - rsp.msg.status = AcceptNewFriend(v3, v4, scene); - if (rsp.msg.status != 1) { - LOG_ERROR("AcceptNewFriend failed: {}", rsp.msg.status); - } - } - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_RECV_TRANSFER; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - rsp.msg.status = ReceiveTransfer(wxid, tfid, taid); - if (rsp.msg.status != 1) { - LOG_ERROR("AddChatroomMember failed: {}", rsp.msg.status); - } - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_decrypt_image(char *src, char *dst, uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_DECRYPT_IMAGE; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - rsp.msg.status = (int)DecryptImage(src, dst); - if (rsp.msg.status != 1) { - LOG_ERROR("DecryptImage failed."); - } - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_add_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_ADD_ROOM_MEMBERS; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - rsp.msg.status = AddChatroomMember(roomid, wxids); - if (rsp.msg.status != 1) { - LOG_ERROR("AddChatroomMember failed: {}", rsp.msg.status); - } - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -bool func_del_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) -{ - Response rsp = Response_init_default; - rsp.func = Functions_FUNC_DEL_ROOM_MEMBERS; - rsp.which_msg = Response_status_tag; - rsp.msg.status = 0; - - rsp.msg.status = DelChatroomMember(roomid, wxids); - if (rsp.msg.status != 1) { - LOG_ERROR("DelChatroomMember failed: {}", rsp.msg.status); - } - - pb_ostream_t stream = pb_ostream_from_buffer(out, *len); - if (!pb_encode(&stream, Response_fields, &rsp)) { - LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); - return false; - } - *len = stream.bytes_written; - - return true; -} - -static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) -{ - bool ret = false; - Request req = Request_init_default; - pb_istream_t stream = pb_istream_from_buffer(in, in_len); - if (!pb_decode(&stream, Request_fields, &req)) { - LOG_ERROR("Decoding failed: {}", PB_GET_ERROR(&stream)); - pb_release(Request_fields, &req); - return false; - } - - LOG_DEBUG("Func: {:#x} Data: {}", (uint8_t)req.func, in_len); - switch (req.func) { - case Functions_FUNC_IS_LOGIN: { - LOG_DEBUG("[Functions_FUNC_IS_LOGIN]"); - ret = func_is_login(out, out_len); - break; - } - case Functions_FUNC_GET_SELF_WXID: { - LOG_DEBUG("[Functions_FUNC_GET_SELF_WXID]"); - ret = func_get_self_wxid(out, out_len); - break; - } - case Functions_FUNC_GET_MSG_TYPES: { - LOG_DEBUG("[Functions_FUNC_GET_MSG_TYPES]"); - ret = func_get_msg_types(out, out_len); - break; - } - case Functions_FUNC_GET_CONTACTS: { - LOG_DEBUG("[Functions_FUNC_GET_CONTACTS]"); - ret = func_get_contacts(out, out_len); - break; - } - case Functions_FUNC_GET_DB_NAMES: { - LOG_DEBUG("[Functions_FUNC_GET_DB_NAMES]"); - ret = func_get_db_names(out, out_len); - break; - } - case Functions_FUNC_GET_DB_TABLES: { - LOG_DEBUG("[Functions_FUNC_GET_DB_TABLES]"); - ret = func_get_db_tables(req.msg.str, out, out_len); - break; - } - case Functions_FUNC_GET_USER_INFO: { - LOG_DEBUG("[Functions_FUNC_GET_USER_INFO]"); - ret = func_get_user_info(out, out_len); - break; - } - case Functions_FUNC_SEND_TXT: { - LOG_DEBUG("[Functions_FUNC_SEND_TXT]"); - ret = func_send_txt(req.msg.txt, out, out_len); - break; - } - case Functions_FUNC_SEND_IMG: { - LOG_DEBUG("[Functions_FUNC_SEND_IMG]"); - ret = func_send_img(req.msg.file.path, req.msg.file.receiver, out, out_len); - break; - } - case Functions_FUNC_SEND_FILE: { - LOG_DEBUG("[Functions_FUNC_SEND_FILE]"); - ret = func_send_file(req.msg.file.path, req.msg.file.receiver, out, out_len); - break; - } -#if 0 - case Functions_FUNC_SEND_XML: { - LOG_DEBUG("[Functions_FUNC_SEND_XML]"); - ret = func_send_xml(req.msg.xml, out, out_len); - break; - } - case Functions_FUNC_SEND_EMOTION: { - LOG_DEBUG("[Functions_FUNC_SEND_EMOTION]"); - ret = func_send_emotion(req.msg.file.path, req.msg.file.receiver, out, out_len); - break; - } -#endif - case Functions_FUNC_ENABLE_RECV_TXT: { - LOG_DEBUG("[Functions_FUNC_ENABLE_RECV_TXT]"); - ret = func_enable_recv_txt(out, out_len); - break; - } - case Functions_FUNC_DISABLE_RECV_TXT: { - LOG_DEBUG("[Functions_FUNC_DISABLE_RECV_TXT]"); - ret = func_disable_recv_txt(out, out_len); - break; - } - case Functions_FUNC_EXEC_DB_QUERY: { - LOG_DEBUG("[Functions_FUNC_EXEC_DB_QUERY]"); - ret = func_exec_db_query(req.msg.query.db, req.msg.query.sql, out, out_len); - break; - } - case Functions_FUNC_ACCEPT_FRIEND: { - LOG_DEBUG("[Functions_FUNC_ACCEPT_FRIEND]"); - ret = func_accept_friend(req.msg.v.v3, req.msg.v.v4, req.msg.v.scene, out, out_len); - break; - } - case Functions_FUNC_RECV_TRANSFER: { - LOG_DEBUG("[Functions_FUNC_RECV_TRANSFER]"); - ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tfid, req.msg.tf.taid, out, out_len); - break; - } - case Functions_FUNC_DECRYPT_IMAGE: { - LOG_DEBUG("[FUNCTIONS_FUNC_DECRYPT_IMAGE]"); - ret = func_decrypt_image(req.msg.dec.src, req.msg.dec.dst, out, out_len); - break; - } - case Functions_FUNC_ADD_ROOM_MEMBERS: { - LOG_DEBUG("[Functions_FUNC_ADD_ROOM_MEMBERS]"); - ret = func_add_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len); - break; - } - case Functions_FUNC_DEL_ROOM_MEMBERS: { - LOG_DEBUG("[Functions_FUNC_DEL_ROOM_MEMBERS]"); - ret = func_del_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len); - break; - } - default: { - LOG_ERROR("[UNKNOW FUNCTION]"); - break; - } - } - pb_release(Request_fields, &req); - return ret; -} - -static int RunServer() -{ - int rv = 0; - char url[URL_SIZE + 1] = { 0 }; - sprintf_s(url, URL_SIZE, "%s:%d", BASE_URL, lport); - if ((rv = nng_pair1_open(&sock)) != 0) { - LOG_ERROR("nng_pair0_open error {}", nng_strerror(rv)); - return rv; - } - - if ((rv = nng_listen(sock, (char *)url, NULL, 0)) != 0) { - LOG_ERROR("nng_listen error {}", nng_strerror(rv)); - return rv; - } - - LOG_INFO("CMD Server listening on {}", (char *)url); - if ((rv = nng_setopt_ms(sock, NNG_OPT_SENDTIMEO, 1000)) != 0) { - LOG_ERROR("nng_setopt_ms error: {}", nng_strerror(rv)); - return rv; - } - - lIsRunning = true; - while (lIsRunning) { - uint8_t *in = NULL; - size_t in_len, out_len = G_BUF_SIZE; - if ((rv = nng_recv(sock, &in, &in_len, NNG_FLAG_ALLOC)) != 0) { - LOG_ERROR("nng_recv error: {}", nng_strerror(rv)); - break; - } - - // LOG_BUFFER(in, in_len); - if (dispatcher(in, in_len, gBuffer, &out_len)) { - LOG_DEBUG("Send data length {}", out_len); - // LOG_BUFFER(gBuffer, out_len); - rv = nng_send(sock, gBuffer, out_len, 0); - if (rv != 0) { - LOG_ERROR("nng_send: {}", nng_strerror(rv)); - } - - } else { - // Error - LOG_ERROR("Dispatcher failed..."); - rv = nng_send(sock, gBuffer, 0, 0); - if (rv != 0) { - LOG_ERROR("nng_send: {}", nng_strerror(rv)); - } - // break; - } - nng_free(in, in_len); - } - LOG_DEBUG("Leave RunServer"); - return rv; -} - -int RpcStartServer(int port) -{ - if (lIsRunning) { - return 0; - } - - lport = port; - - HANDLE rpcThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RunServer, NULL, NULL, &lThreadId); - if (rpcThread != 0) { - CloseHandle(rpcThread); - } - - return 0; -} - -int RpcStopServer() -{ - if (lIsRunning) { - nng_close(sock); - UnListenMessage(); - lIsRunning = false; - Sleep(1000); - LOG_INFO("Server stoped."); - } - return 0; -} +#pragma warning(disable : 4251) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "wcf.pb.h" + +#include "chatroom_mgmt.h" +#include "contact_mgmt.h" +#include "decrypt_image.h" +#include "exec_sql.h" +#include "log.h" +#include "pb_types.h" +#include "pb_util.h" +#include "receive_msg.h" +#include "receive_transfer.h" +#include "rpc_server.h" +#include "send_msg.h" +#include "spy.h" +#include "spy_types.h" +#include "user_info.h" +#include "util.h" + +#define URL_SIZE 20 +#define BASE_URL "tcp://0.0.0.0" +#define G_BUF_SIZE (16 * 1024 * 1024) + +extern int IsLogin(void); // Defined in spy.cpp + +bool gIsListening; +mutex gMutex; +condition_variable gCV; +queue gMsgQueue; + +static int lport = 0; +static DWORD lThreadId = 0; +static bool lIsRunning = false; +static nng_socket sock; +static uint8_t gBuffer[G_BUF_SIZE] = { 0 }; + +bool func_is_login(uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_IS_LOGIN; + rsp.which_msg = Response_status_tag; + rsp.msg.status = IsLogin(); + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_get_self_wxid(uint8_t *out, size_t *len) +{ + string wxid = GetSelfWxid(); + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_GET_SELF_WXID; + rsp.which_msg = Response_str_tag; + rsp.msg.str = (char *)wxid.c_str(); + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_get_msg_types(uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_GET_MSG_TYPES; + rsp.which_msg = Response_types_tag; + + MsgTypes_t types = GetMsgTypes(); + rsp.msg.types.types.funcs.encode = encode_types; + rsp.msg.types.types.arg = &types; + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_get_contacts(uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_GET_CONTACTS; + rsp.which_msg = Response_contacts_tag; + + vector contacts = GetContacts(); + rsp.msg.contacts.contacts.funcs.encode = encode_contacts; + rsp.msg.contacts.contacts.arg = &contacts; + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_get_db_names(uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_GET_DB_NAMES; + rsp.which_msg = Response_dbs_tag; + + DbNames_t dbnames = GetDbNames(); + rsp.msg.dbs.names.funcs.encode = encode_dbnames; + rsp.msg.dbs.names.arg = &dbnames; + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_get_db_tables(char *db, uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_GET_DB_TABLES; + rsp.which_msg = Response_tables_tag; + + DbTables_t tables = GetDbTables(db); + rsp.msg.tables.tables.funcs.encode = encode_tables; + rsp.msg.tables.tables.arg = &tables; + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_get_user_info(uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_GET_USER_INFO; + rsp.which_msg = Response_ui_tag; + + UserInfo_t ui = GetUserInfo(); + rsp.msg.ui.wxid = (char *)ui.wxid.c_str(); + rsp.msg.ui.name = (char *)ui.name.c_str(); + rsp.msg.ui.mobile = (char *)ui.mobile.c_str(); + rsp.msg.ui.home = (char *)ui.home.c_str(); + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_send_txt(TextMsg txt, uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_SEND_TXT; + rsp.which_msg = Response_status_tag; + rsp.msg.status = 0; + + if ((txt.msg == NULL) || (txt.receiver == NULL)) { + rsp.msg.status = -1; // Empty message or empty receiver + } else { + string msg(txt.msg); + string receiver(txt.receiver); + string aters(txt.aters ? txt.aters : ""); + + SendTextMessage(receiver, msg, aters); + } + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_send_img(char *path, char *receiver, uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_SEND_IMG; + rsp.which_msg = Response_status_tag; + rsp.msg.status = 0; + + if ((path == NULL) || (receiver == NULL)) { + rsp.msg.status = -1; + } else { + SendImageMessage(receiver, path); + } + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_send_file(char *path, char *receiver, uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_SEND_IMG; + rsp.which_msg = Response_status_tag; + rsp.msg.status = 0; + + if ((path == NULL) || (receiver == NULL)) { + rsp.msg.status = -1; + } else { + SendImageMessage(receiver, path); + } + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_send_xml(XmlMsg xml, uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_SEND_XML; + rsp.which_msg = Response_status_tag; + rsp.msg.status = 0; + + if ((xml.content == NULL) || (xml.receiver == NULL)) { + rsp.msg.status = -1; + } else { + string receiver(xml.receiver); + string content(xml.content); + string path(xml.path ? xml.path : ""); + uint32_t type = (uint32_t)xml.type; + SendXmlMessage(receiver, content, path, type); + } + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_send_emotion(char *path, char *receiver, uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_SEND_EMOTION; + rsp.which_msg = Response_status_tag; + rsp.msg.status = 0; + + if ((path == NULL) || (receiver == NULL)) { + rsp.msg.status = -1; + } else { + SendEmotionMessage(receiver, path); + } + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +static void PushMessage() +{ + static nng_socket msg_sock; + static uint8_t buffer[G_BUF_SIZE] = { 0 }; + + int rv; + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_ENABLE_RECV_TXT; + rsp.which_msg = Response_wxmsg_tag; + + pb_ostream_t stream = pb_ostream_from_buffer(buffer, G_BUF_SIZE); + + char url[URL_SIZE + 1] = { 0 }; + sprintf_s(url, URL_SIZE, "%s:%d", BASE_URL, lport + 1); + LOG_ERROR("URL: {}", url); + if ((rv = nng_pair1_open(&msg_sock)) != 0) { + LOG_ERROR("nng_pair0_open error {}", nng_strerror(rv)); + return; + } + + if ((rv = nng_listen(msg_sock, url, NULL, 0)) != 0) { + LOG_ERROR("nng_listen error {}", nng_strerror(rv)); + return; + } + + LOG_INFO("MSG Server listening on {}", url); + if ((rv = nng_setopt_ms(msg_sock, NNG_OPT_SENDTIMEO, 2000)) != 0) { + LOG_ERROR("nng_setopt_ms: {}", nng_strerror(rv)); + return; + } + + while (gIsListening) { + unique_lock lock(gMutex); + if (gCV.wait_for(lock, chrono::milliseconds(1000), []() { return !gMsgQueue.empty(); })) { + while (!gMsgQueue.empty()) { + auto wxmsg = gMsgQueue.front(); + rsp.msg.wxmsg.is_self = wxmsg.is_self; + rsp.msg.wxmsg.is_group = wxmsg.is_group; + rsp.msg.wxmsg.type = wxmsg.type; + rsp.msg.wxmsg.id = (char *)wxmsg.id.c_str(); + rsp.msg.wxmsg.xml = (char *)wxmsg.xml.c_str(); + rsp.msg.wxmsg.sender = (char *)wxmsg.sender.c_str(); + rsp.msg.wxmsg.roomid = (char *)wxmsg.roomid.c_str(); + rsp.msg.wxmsg.content = (char *)wxmsg.content.c_str(); + rsp.msg.wxmsg.thumb = (char *)wxmsg.thumb.c_str(); + rsp.msg.wxmsg.extra = (char *)wxmsg.extra.c_str(); + gMsgQueue.pop(); + LOG_DEBUG("Recv msg: {}", wxmsg.content); + pb_ostream_t stream = pb_ostream_from_buffer(buffer, G_BUF_SIZE); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + continue; + } + + rv = nng_send(msg_sock, buffer, stream.bytes_written, 0); + if (rv != 0) { + LOG_ERROR("nng_send: {}", nng_strerror(rv)); + } + LOG_DEBUG("Send data length {}", stream.bytes_written); + } + } + } + nng_close(msg_sock); +} + +bool func_enable_recv_txt(uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_ENABLE_RECV_TXT; + rsp.which_msg = Response_status_tag; + rsp.msg.status = -1; + + ListenMessage(); + HANDLE msgThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PushMessage, NULL, NULL, NULL); + if (msgThread != 0) { + CloseHandle(msgThread); + rsp.msg.status = 0; + } + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_disable_recv_txt(uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_DISABLE_RECV_TXT; + rsp.which_msg = Response_status_tag; + rsp.msg.status = 0; + + UnListenMessage(); // 可能需要1秒之后才能退出,见 PushMessage + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_exec_db_query(char *db, char *sql, uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_GET_DB_TABLES; + rsp.which_msg = Response_rows_tag; + + DbRows_t rows = ExecDbQuery(db, sql); + rsp.msg.rows.rows.arg = &rows; + rsp.msg.rows.rows.funcs.encode = encode_rows; + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_accept_friend(char *v3, char *v4, int32_t scene, uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_SEND_IMG; + rsp.which_msg = Response_status_tag; + rsp.msg.status = 0; + + if ((v3 == NULL) || (v4 == NULL)) { + rsp.msg.status = -1; + LOG_ERROR("Empty V3 or V4."); + } else { + rsp.msg.status = AcceptNewFriend(v3, v4, scene); + if (rsp.msg.status != 1) { + LOG_ERROR("AcceptNewFriend failed: {}", rsp.msg.status); + } + } + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_receive_transfer(char *wxid, char *tfid, char *taid, uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_RECV_TRANSFER; + rsp.which_msg = Response_status_tag; + rsp.msg.status = 0; + + rsp.msg.status = ReceiveTransfer(wxid, tfid, taid); + if (rsp.msg.status != 1) { + LOG_ERROR("AddChatroomMember failed: {}", rsp.msg.status); + } + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_decrypt_image(char *src, char *dst, uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_DECRYPT_IMAGE; + rsp.which_msg = Response_status_tag; + rsp.msg.status = 0; + + rsp.msg.status = (int)DecryptImage(src, dst); + if (rsp.msg.status != 1) { + LOG_ERROR("DecryptImage failed."); + } + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_add_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_ADD_ROOM_MEMBERS; + rsp.which_msg = Response_status_tag; + rsp.msg.status = 0; + + rsp.msg.status = AddChatroomMember(roomid, wxids); + if (rsp.msg.status != 1) { + LOG_ERROR("AddChatroomMember failed: {}", rsp.msg.status); + } + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +bool func_del_room_members(char *roomid, char *wxids, uint8_t *out, size_t *len) +{ + Response rsp = Response_init_default; + rsp.func = Functions_FUNC_DEL_ROOM_MEMBERS; + rsp.which_msg = Response_status_tag; + rsp.msg.status = 0; + + rsp.msg.status = DelChatroomMember(roomid, wxids); + if (rsp.msg.status != 1) { + LOG_ERROR("DelChatroomMember failed: {}", rsp.msg.status); + } + + pb_ostream_t stream = pb_ostream_from_buffer(out, *len); + if (!pb_encode(&stream, Response_fields, &rsp)) { + LOG_ERROR("Encoding failed: {}", PB_GET_ERROR(&stream)); + return false; + } + *len = stream.bytes_written; + + return true; +} + +static bool dispatcher(uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len) +{ + bool ret = false; + Request req = Request_init_default; + pb_istream_t stream = pb_istream_from_buffer(in, in_len); + if (!pb_decode(&stream, Request_fields, &req)) { + LOG_ERROR("Decoding failed: {}", PB_GET_ERROR(&stream)); + pb_release(Request_fields, &req); + return false; + } + + LOG_DEBUG("Func: {:#x} Data: {}", (uint8_t)req.func, in_len); + switch (req.func) { + case Functions_FUNC_IS_LOGIN: { + LOG_DEBUG("[Functions_FUNC_IS_LOGIN]"); + ret = func_is_login(out, out_len); + break; + } + case Functions_FUNC_GET_SELF_WXID: { + LOG_DEBUG("[Functions_FUNC_GET_SELF_WXID]"); + ret = func_get_self_wxid(out, out_len); + break; + } + case Functions_FUNC_GET_MSG_TYPES: { + LOG_DEBUG("[Functions_FUNC_GET_MSG_TYPES]"); + ret = func_get_msg_types(out, out_len); + break; + } + case Functions_FUNC_GET_CONTACTS: { + LOG_DEBUG("[Functions_FUNC_GET_CONTACTS]"); + ret = func_get_contacts(out, out_len); + break; + } + case Functions_FUNC_GET_DB_NAMES: { + LOG_DEBUG("[Functions_FUNC_GET_DB_NAMES]"); + ret = func_get_db_names(out, out_len); + break; + } + case Functions_FUNC_GET_DB_TABLES: { + LOG_DEBUG("[Functions_FUNC_GET_DB_TABLES]"); + ret = func_get_db_tables(req.msg.str, out, out_len); + break; + } + case Functions_FUNC_GET_USER_INFO: { + LOG_DEBUG("[Functions_FUNC_GET_USER_INFO]"); + ret = func_get_user_info(out, out_len); + break; + } + case Functions_FUNC_SEND_TXT: { + LOG_DEBUG("[Functions_FUNC_SEND_TXT]"); + ret = func_send_txt(req.msg.txt, out, out_len); + break; + } + case Functions_FUNC_SEND_IMG: { + LOG_DEBUG("[Functions_FUNC_SEND_IMG]"); + ret = func_send_img(req.msg.file.path, req.msg.file.receiver, out, out_len); + break; + } + case Functions_FUNC_SEND_FILE: { + LOG_DEBUG("[Functions_FUNC_SEND_FILE]"); + ret = func_send_file(req.msg.file.path, req.msg.file.receiver, out, out_len); + break; + } +#if 0 + case Functions_FUNC_SEND_XML: { + LOG_DEBUG("[Functions_FUNC_SEND_XML]"); + ret = func_send_xml(req.msg.xml, out, out_len); + break; + } + case Functions_FUNC_SEND_EMOTION: { + LOG_DEBUG("[Functions_FUNC_SEND_EMOTION]"); + ret = func_send_emotion(req.msg.file.path, req.msg.file.receiver, out, out_len); + break; + } +#endif + case Functions_FUNC_ENABLE_RECV_TXT: { + LOG_DEBUG("[Functions_FUNC_ENABLE_RECV_TXT]"); + ret = func_enable_recv_txt(out, out_len); + break; + } + case Functions_FUNC_DISABLE_RECV_TXT: { + LOG_DEBUG("[Functions_FUNC_DISABLE_RECV_TXT]"); + ret = func_disable_recv_txt(out, out_len); + break; + } + case Functions_FUNC_EXEC_DB_QUERY: { + LOG_DEBUG("[Functions_FUNC_EXEC_DB_QUERY]"); + ret = func_exec_db_query(req.msg.query.db, req.msg.query.sql, out, out_len); + break; + } + case Functions_FUNC_ACCEPT_FRIEND: { + LOG_DEBUG("[Functions_FUNC_ACCEPT_FRIEND]"); + ret = func_accept_friend(req.msg.v.v3, req.msg.v.v4, req.msg.v.scene, out, out_len); + break; + } + case Functions_FUNC_RECV_TRANSFER: { + LOG_DEBUG("[Functions_FUNC_RECV_TRANSFER]"); + ret = func_receive_transfer(req.msg.tf.wxid, req.msg.tf.tfid, req.msg.tf.taid, out, out_len); + break; + } + case Functions_FUNC_DECRYPT_IMAGE: { + LOG_DEBUG("[FUNCTIONS_FUNC_DECRYPT_IMAGE]"); + ret = func_decrypt_image(req.msg.dec.src, req.msg.dec.dst, out, out_len); + break; + } + case Functions_FUNC_ADD_ROOM_MEMBERS: { + LOG_DEBUG("[Functions_FUNC_ADD_ROOM_MEMBERS]"); + ret = func_add_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len); + break; + } + case Functions_FUNC_DEL_ROOM_MEMBERS: { + LOG_DEBUG("[Functions_FUNC_DEL_ROOM_MEMBERS]"); + ret = func_del_room_members(req.msg.m.roomid, req.msg.m.wxids, out, out_len); + break; + } + default: { + LOG_ERROR("[UNKNOW FUNCTION]"); + break; + } + } + pb_release(Request_fields, &req); + return ret; +} + +static int RunServer() +{ + int rv = 0; + char url[URL_SIZE + 1] = { 0 }; + sprintf_s(url, URL_SIZE, "%s:%d", BASE_URL, lport); + if ((rv = nng_pair1_open(&sock)) != 0) { + LOG_ERROR("nng_pair0_open error {}", nng_strerror(rv)); + return rv; + } + + if ((rv = nng_listen(sock, (char *)url, NULL, 0)) != 0) { + LOG_ERROR("nng_listen error {}", nng_strerror(rv)); + return rv; + } + + LOG_INFO("CMD Server listening on {}", (char *)url); + if ((rv = nng_setopt_ms(sock, NNG_OPT_SENDTIMEO, 1000)) != 0) { + LOG_ERROR("nng_setopt_ms error: {}", nng_strerror(rv)); + return rv; + } + + lIsRunning = true; + while (lIsRunning) { + uint8_t *in = NULL; + size_t in_len, out_len = G_BUF_SIZE; + if ((rv = nng_recv(sock, &in, &in_len, NNG_FLAG_ALLOC)) != 0) { + LOG_ERROR("nng_recv error: {}", nng_strerror(rv)); + break; + } + + // LOG_BUFFER(in, in_len); + if (dispatcher(in, in_len, gBuffer, &out_len)) { + LOG_DEBUG("Send data length {}", out_len); + // LOG_BUFFER(gBuffer, out_len); + rv = nng_send(sock, gBuffer, out_len, 0); + if (rv != 0) { + LOG_ERROR("nng_send: {}", nng_strerror(rv)); + } + + } else { + // Error + LOG_ERROR("Dispatcher failed..."); + rv = nng_send(sock, gBuffer, 0, 0); + if (rv != 0) { + LOG_ERROR("nng_send: {}", nng_strerror(rv)); + } + // break; + } + nng_free(in, in_len); + } + LOG_DEBUG("Leave RunServer"); + return rv; +} + +int RpcStartServer(int port) +{ + if (lIsRunning) { + return 0; + } + + lport = port; + + HANDLE rpcThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RunServer, NULL, NULL, &lThreadId); + if (rpcThread != 0) { + CloseHandle(rpcThread); + } + + return 0; +} + +int RpcStopServer() +{ + if (lIsRunning) { + nng_close(sock); + UnListenMessage(); + lIsRunning = false; + Sleep(1000); + LOG_INFO("Server stoped."); + } + return 0; +} diff --git a/spy/rpc_server.h b/WeChatFerry/spy/rpc_server.h similarity index 94% rename from spy/rpc_server.h rename to WeChatFerry/spy/rpc_server.h index 7722d33..3bc31e1 100644 --- a/spy/rpc_server.h +++ b/WeChatFerry/spy/rpc_server.h @@ -1,10 +1,10 @@ -#pragma once - -#ifdef SPY_EXPORTS -#define SPY_API __declspec(dllexport) -#else -#define SPY_API __declspec(dllimport) -#endif - -int RpcStartServer(int port); -int RpcStopServer(); +#pragma once + +#ifdef SPY_EXPORTS +#define SPY_API __declspec(dllexport) +#else +#define SPY_API __declspec(dllimport) +#endif + +int RpcStartServer(int port); +int RpcStopServer(); diff --git a/spy/send_msg.cpp b/WeChatFerry/spy/send_msg.cpp similarity index 96% rename from spy/send_msg.cpp rename to WeChatFerry/spy/send_msg.cpp index a53e306..795f6bf 100644 --- a/spy/send_msg.cpp +++ b/WeChatFerry/spy/send_msg.cpp @@ -1,342 +1,342 @@ -#include "framework.h" -#include -#include - -#include "send_msg.h" -#include "spy_types.h" -#include "util.h" - -extern HANDLE g_hEvent; -extern WxCalls_t g_WxCalls; -extern DWORD g_WeChatWinDllAddr; -extern string GetSelfWxid(); // Defined in spy.cpp - -void SendTextMessage(string wxid, string msg, string atWxids) -{ - int success = 0; - char buffer[0x2D8] = { 0 }; - WxString_t wxMsg = { 0 }; - WxString_t wxWxid = { 0 }; - - // 发送消息Call地址 = 微信基址 + 偏移 - DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendText.call1; - DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendText.call2; - DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendText.call3; - - wstring wsWxid = String2Wstring(wxid); - wstring wsMsg = String2Wstring(msg); - - wxMsg.text = (wchar_t *)wsMsg.c_str(); - wxMsg.size = wsMsg.size(); - wxMsg.capacity = wsMsg.capacity(); - - wxWxid.text = (wchar_t *)wsWxid.c_str(); - wxWxid.size = wsWxid.size(); - wxWxid.capacity = wsWxid.capacity(); - - vector vTxtAtWxids; - if (!atWxids.empty()) { - vector vAtWxids; - wstringstream wss(String2Wstring(atWxids)); - while (wss.good()) { - wstring wstr; - getline(wss, wstr, L','); - vAtWxids.push_back(wstr); - WxString_t txtAtWxid = { 0 }; - txtAtWxid.text = (wchar_t *)vAtWxids.back().c_str(); - txtAtWxid.size = vAtWxids.back().size(); - txtAtWxid.capacity = vAtWxids.back().capacity(); - vTxtAtWxids.push_back(txtAtWxid); - } - } - - __asm - { - pushad; - call sendCall1; - push 0x0; - push 0x0; - push 0x0; - push 0x1; - lea eax, vTxtAtWxids; - push eax; - lea eax, wxMsg; - push eax; - lea edx, wxWxid; - lea ecx, buffer; - call sendCall2; - mov success, eax; - add esp, 0x18; - lea ecx, buffer; - call sendCall3; - popad; - } -} - -void SendImageMessage(string wxid, string path) -{ - if (g_WeChatWinDllAddr == 0) { - return; - } - int success = 0; - DWORD tmpEAX = 0; - char buf[0x2D8] = { 0 }; - WxString_t imgWxid = { 0 }; - WxString_t imgPath = { 0 }; - WxString_t nullbuffer = { 0 }; - - wstring wsWxid = String2Wstring(wxid); - wstring wspath = String2Wstring(path); - - imgWxid.text = (wchar_t *)wsWxid.c_str(); - imgWxid.size = wsWxid.size(); - imgWxid.capacity = wsWxid.capacity(); - - imgPath.text = (wchar_t *)wspath.c_str(); - imgPath.size = wspath.size(); - imgPath.capacity = wspath.capacity(); - - // 发送图片Call地址 = 微信基址 + 偏移 - DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call1; - DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call2; - DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call3; - DWORD sendCall4 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call4; - - __asm { - pushad; - call sendCall1; - sub esp,0x14; - mov tmpEAX,eax; - lea eax,nullbuffer; - mov ecx,esp; - lea edi,imgPath; - push eax; - call sendCall2; - mov ecx,dword ptr [tmpEAX]; - lea eax,imgWxid; - push edi; - push eax; - lea eax,buf; - push eax; - call sendCall3; - mov success,eax; - lea ecx,buf; - call sendCall4; - popad; - } -} - -void SendFileMessage(string wxid, string path) -{ - if (g_WeChatWinDllAddr == 0) { - return; - } - int success = 0; - DWORD tmpEAX = 0; - char buffer[0x2D8] = { 0 }; - WxString_t fileWxid = { 0 }; - WxString_t filePath = { 0 }; - WxString_t nullbuffer = { 0 }; - - wstring wsWxid = String2Wstring(wxid); - wstring wspath = String2Wstring(path); - - fileWxid.text = (wchar_t *)wsWxid.c_str(); - fileWxid.size = wsWxid.size(); - fileWxid.capacity = wsWxid.capacity(); - - filePath.text = (wchar_t *)wspath.c_str(); - filePath.size = wspath.size(); - filePath.capacity = wspath.capacity(); - - // 发送文件Call地址 = 微信基址 + 偏移 - DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call1; - DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call2; - DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call3; - DWORD sendCall4 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call4; - - __asm { - pushad; - pushfd; - call sendCall1; - sub esp, 0x14; - mov tmpEAX, eax; - lea eax, nullbuffer; - mov ecx, esp; - push eax; - call sendCall2; - push 0x0; - sub esp, 0x14; - mov edi, esp; - mov dword ptr[edi], 0; - mov dword ptr[edi + 0x4], 0; - mov dword ptr[edi + 0x8], 0; - mov dword ptr[edi + 0xc], 0; - mov dword ptr[edi + 0x10], 0; - sub esp, 0x14; - lea eax, filePath; - mov ecx, esp; - push eax; - call sendCall2; - sub esp, 0x14; - lea eax, fileWxid; - mov ecx, esp; - push eax; - call sendCall2; - mov ecx, dword ptr[tmpEAX]; - lea eax, buffer; - push eax; - call sendCall3; - mov al, byte ptr[eax + 0x38]; - movzx eax, al; - mov success, eax; - lea ecx, buffer; - call sendCall4; - popfd; - popad; - } -} -void SendXmlMessage(string receiver, string xml, string path, int type) -{ - if (g_WeChatWinDllAddr == 0) { - return; - } - - // 发送消息Call地址 = 微信基址 + 偏移 - DWORD sendXmlCall1 = g_WeChatWinDllAddr + g_WxCalls.sendXml.call1; - DWORD sendXmlCall2 = g_WeChatWinDllAddr + g_WxCalls.sendXml.call2; - DWORD sendXmlCall3 = g_WeChatWinDllAddr + g_WxCalls.sendXml.call3; - DWORD sendXmlCall4 = g_WeChatWinDllAddr + g_WxCalls.sendXml.call4; - DWORD sendXmlParam = g_WeChatWinDllAddr + g_WxCalls.sendXml.param; - - char buffer[0xFF0] = { 0 }; - char nullBuf[0x1C] = { 0 }; - WxString_t wxReceiver = { 0 }; - WxString_t wxXml = { 0 }; - WxString_t wxPath = { 0 }; - WxString_t wxNull = { 0 }; - WxString_t wxSender = { 0 }; - - wstring wsSender = String2Wstring(GetSelfWxid()); - wstring wsReceiver = String2Wstring(receiver); - wstring wsXml = String2Wstring(xml); - - wxReceiver.text = (wchar_t *)wsReceiver.c_str(); - wxReceiver.size = wsReceiver.size(); - wxReceiver.capacity = wsReceiver.capacity(); - - wxXml.text = (wchar_t *)wsXml.c_str(); - wxXml.size = wsXml.size(); - wxXml.capacity = wsXml.capacity(); - - wxSender.text = (wchar_t *)wsSender.c_str(); - wxSender.size = wsSender.size(); - wxSender.capacity = wsSender.capacity(); - - if (!path.empty()) { - wstring wsPath = String2Wstring(path); - wxPath.text = (wchar_t *)wsPath.c_str(); - wxPath.size = wsPath.size(); - wxPath.capacity = wsPath.capacity(); - } - - DWORD sendtype = type; - __asm { - pushad; - pushfd; - lea ecx, buffer; - call sendXmlCall1; - mov eax, [sendtype]; - push eax; - lea eax, nullBuf; - lea edx, wxSender; - push eax; - lea eax, wxPath; - push eax; - lea eax, wxXml; - push eax; - lea edi, wxReceiver; - push edi; - lea ecx, buffer; - call sendXmlCall2; - add esp, 0x14; - lea eax, wxNull; - push eax; - lea ecx, buffer; - call sendXmlCall3; - mov dl, 0x0; - lea ecx, buffer; - push sendXmlParam; - push sendXmlParam; - call sendXmlCall4; - add esp, 0x8; - popfd; - popad; - } -} - -void SendEmotionMessage(string wxid, string path) -{ - if (g_WeChatWinDllAddr == 0) { - return; - } - - char buffer[0x1C] = { 0 }; - WxString_t emoWxid = { 0 }; - WxString_t emoPath = { 0 }; - WxString_t nullbuffer = { 0 }; - - wstring wsWxid = String2Wstring(wxid); - wstring wspath = String2Wstring(path); - - emoWxid.text = (wchar_t *)wsWxid.c_str(); - emoWxid.size = wsWxid.size(); - emoWxid.capacity = wsWxid.capacity(); - - emoPath.text = (wchar_t *)wspath.c_str(); - emoPath.size = wspath.size(); - emoPath.capacity = wspath.capacity(); - - // 发送文件Call地址 = 微信基址 + 偏移 - DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendEmo.call1; - DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendEmo.call2; - DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendEmo.call3; - - __asm { - pushad; - pushfd; - mov ebx, dword ptr[sendCall3]; - lea eax, buffer; - push eax; - push 0x0; - sub esp, 0x14; - mov esi, esp; - mov dword ptr [esi], 0x0; - mov dword ptr [esi+0x4], 0x0; - mov dword ptr [esi+0x8], 0x0; - mov dword ptr [esi+0xC], 0x0; - mov dword ptr [esi+0x10], 0x0; - push 0x2; - lea eax, emoWxid; - sub esp, 0x14; - mov ecx, esp; - push eax; - call sendCall1; - sub esp, 0x14; - mov esi, esp; - mov dword ptr [esi], 0x0; - mov dword ptr [esi+0x4], 0x0; - mov dword ptr [esi+0x8], 0x0; - mov dword ptr [esi+0xC], 0x0; - mov dword ptr [esi+0x10], 0x0; - sub esp, 0x14; - mov ecx, esp; - lea eax, emoPath; - push eax; - call sendCall1; - mov ecx, ebx; - call sendCall2; - popfd; - popad; - } -} +#include "framework.h" +#include +#include + +#include "send_msg.h" +#include "spy_types.h" +#include "util.h" + +extern HANDLE g_hEvent; +extern WxCalls_t g_WxCalls; +extern DWORD g_WeChatWinDllAddr; +extern string GetSelfWxid(); // Defined in spy.cpp + +void SendTextMessage(string wxid, string msg, string atWxids) +{ + int success = 0; + char buffer[0x2D8] = { 0 }; + WxString_t wxMsg = { 0 }; + WxString_t wxWxid = { 0 }; + + // 发送消息Call地址 = 微信基址 + 偏移 + DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendText.call1; + DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendText.call2; + DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendText.call3; + + wstring wsWxid = String2Wstring(wxid); + wstring wsMsg = String2Wstring(msg); + + wxMsg.text = (wchar_t *)wsMsg.c_str(); + wxMsg.size = wsMsg.size(); + wxMsg.capacity = wsMsg.capacity(); + + wxWxid.text = (wchar_t *)wsWxid.c_str(); + wxWxid.size = wsWxid.size(); + wxWxid.capacity = wsWxid.capacity(); + + vector vTxtAtWxids; + if (!atWxids.empty()) { + vector vAtWxids; + wstringstream wss(String2Wstring(atWxids)); + while (wss.good()) { + wstring wstr; + getline(wss, wstr, L','); + vAtWxids.push_back(wstr); + WxString_t txtAtWxid = { 0 }; + txtAtWxid.text = (wchar_t *)vAtWxids.back().c_str(); + txtAtWxid.size = vAtWxids.back().size(); + txtAtWxid.capacity = vAtWxids.back().capacity(); + vTxtAtWxids.push_back(txtAtWxid); + } + } + + __asm + { + pushad; + call sendCall1; + push 0x0; + push 0x0; + push 0x0; + push 0x1; + lea eax, vTxtAtWxids; + push eax; + lea eax, wxMsg; + push eax; + lea edx, wxWxid; + lea ecx, buffer; + call sendCall2; + mov success, eax; + add esp, 0x18; + lea ecx, buffer; + call sendCall3; + popad; + } +} + +void SendImageMessage(string wxid, string path) +{ + if (g_WeChatWinDllAddr == 0) { + return; + } + int success = 0; + DWORD tmpEAX = 0; + char buf[0x2D8] = { 0 }; + WxString_t imgWxid = { 0 }; + WxString_t imgPath = { 0 }; + WxString_t nullbuffer = { 0 }; + + wstring wsWxid = String2Wstring(wxid); + wstring wspath = String2Wstring(path); + + imgWxid.text = (wchar_t *)wsWxid.c_str(); + imgWxid.size = wsWxid.size(); + imgWxid.capacity = wsWxid.capacity(); + + imgPath.text = (wchar_t *)wspath.c_str(); + imgPath.size = wspath.size(); + imgPath.capacity = wspath.capacity(); + + // 发送图片Call地址 = 微信基址 + 偏移 + DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call1; + DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call2; + DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call3; + DWORD sendCall4 = g_WeChatWinDllAddr + g_WxCalls.sendImg.call4; + + __asm { + pushad; + call sendCall1; + sub esp,0x14; + mov tmpEAX,eax; + lea eax,nullbuffer; + mov ecx,esp; + lea edi,imgPath; + push eax; + call sendCall2; + mov ecx,dword ptr [tmpEAX]; + lea eax,imgWxid; + push edi; + push eax; + lea eax,buf; + push eax; + call sendCall3; + mov success,eax; + lea ecx,buf; + call sendCall4; + popad; + } +} + +void SendFileMessage(string wxid, string path) +{ + if (g_WeChatWinDllAddr == 0) { + return; + } + int success = 0; + DWORD tmpEAX = 0; + char buffer[0x2D8] = { 0 }; + WxString_t fileWxid = { 0 }; + WxString_t filePath = { 0 }; + WxString_t nullbuffer = { 0 }; + + wstring wsWxid = String2Wstring(wxid); + wstring wspath = String2Wstring(path); + + fileWxid.text = (wchar_t *)wsWxid.c_str(); + fileWxid.size = wsWxid.size(); + fileWxid.capacity = wsWxid.capacity(); + + filePath.text = (wchar_t *)wspath.c_str(); + filePath.size = wspath.size(); + filePath.capacity = wspath.capacity(); + + // 发送文件Call地址 = 微信基址 + 偏移 + DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call1; + DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call2; + DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call3; + DWORD sendCall4 = g_WeChatWinDllAddr + g_WxCalls.sendFile.call4; + + __asm { + pushad; + pushfd; + call sendCall1; + sub esp, 0x14; + mov tmpEAX, eax; + lea eax, nullbuffer; + mov ecx, esp; + push eax; + call sendCall2; + push 0x0; + sub esp, 0x14; + mov edi, esp; + mov dword ptr[edi], 0; + mov dword ptr[edi + 0x4], 0; + mov dword ptr[edi + 0x8], 0; + mov dword ptr[edi + 0xc], 0; + mov dword ptr[edi + 0x10], 0; + sub esp, 0x14; + lea eax, filePath; + mov ecx, esp; + push eax; + call sendCall2; + sub esp, 0x14; + lea eax, fileWxid; + mov ecx, esp; + push eax; + call sendCall2; + mov ecx, dword ptr[tmpEAX]; + lea eax, buffer; + push eax; + call sendCall3; + mov al, byte ptr[eax + 0x38]; + movzx eax, al; + mov success, eax; + lea ecx, buffer; + call sendCall4; + popfd; + popad; + } +} +void SendXmlMessage(string receiver, string xml, string path, int type) +{ + if (g_WeChatWinDllAddr == 0) { + return; + } + + // 发送消息Call地址 = 微信基址 + 偏移 + DWORD sendXmlCall1 = g_WeChatWinDllAddr + g_WxCalls.sendXml.call1; + DWORD sendXmlCall2 = g_WeChatWinDllAddr + g_WxCalls.sendXml.call2; + DWORD sendXmlCall3 = g_WeChatWinDllAddr + g_WxCalls.sendXml.call3; + DWORD sendXmlCall4 = g_WeChatWinDllAddr + g_WxCalls.sendXml.call4; + DWORD sendXmlParam = g_WeChatWinDllAddr + g_WxCalls.sendXml.param; + + char buffer[0xFF0] = { 0 }; + char nullBuf[0x1C] = { 0 }; + WxString_t wxReceiver = { 0 }; + WxString_t wxXml = { 0 }; + WxString_t wxPath = { 0 }; + WxString_t wxNull = { 0 }; + WxString_t wxSender = { 0 }; + + wstring wsSender = String2Wstring(GetSelfWxid()); + wstring wsReceiver = String2Wstring(receiver); + wstring wsXml = String2Wstring(xml); + + wxReceiver.text = (wchar_t *)wsReceiver.c_str(); + wxReceiver.size = wsReceiver.size(); + wxReceiver.capacity = wsReceiver.capacity(); + + wxXml.text = (wchar_t *)wsXml.c_str(); + wxXml.size = wsXml.size(); + wxXml.capacity = wsXml.capacity(); + + wxSender.text = (wchar_t *)wsSender.c_str(); + wxSender.size = wsSender.size(); + wxSender.capacity = wsSender.capacity(); + + if (!path.empty()) { + wstring wsPath = String2Wstring(path); + wxPath.text = (wchar_t *)wsPath.c_str(); + wxPath.size = wsPath.size(); + wxPath.capacity = wsPath.capacity(); + } + + DWORD sendtype = type; + __asm { + pushad; + pushfd; + lea ecx, buffer; + call sendXmlCall1; + mov eax, [sendtype]; + push eax; + lea eax, nullBuf; + lea edx, wxSender; + push eax; + lea eax, wxPath; + push eax; + lea eax, wxXml; + push eax; + lea edi, wxReceiver; + push edi; + lea ecx, buffer; + call sendXmlCall2; + add esp, 0x14; + lea eax, wxNull; + push eax; + lea ecx, buffer; + call sendXmlCall3; + mov dl, 0x0; + lea ecx, buffer; + push sendXmlParam; + push sendXmlParam; + call sendXmlCall4; + add esp, 0x8; + popfd; + popad; + } +} + +void SendEmotionMessage(string wxid, string path) +{ + if (g_WeChatWinDllAddr == 0) { + return; + } + + char buffer[0x1C] = { 0 }; + WxString_t emoWxid = { 0 }; + WxString_t emoPath = { 0 }; + WxString_t nullbuffer = { 0 }; + + wstring wsWxid = String2Wstring(wxid); + wstring wspath = String2Wstring(path); + + emoWxid.text = (wchar_t *)wsWxid.c_str(); + emoWxid.size = wsWxid.size(); + emoWxid.capacity = wsWxid.capacity(); + + emoPath.text = (wchar_t *)wspath.c_str(); + emoPath.size = wspath.size(); + emoPath.capacity = wspath.capacity(); + + // 发送文件Call地址 = 微信基址 + 偏移 + DWORD sendCall1 = g_WeChatWinDllAddr + g_WxCalls.sendEmo.call1; + DWORD sendCall2 = g_WeChatWinDllAddr + g_WxCalls.sendEmo.call2; + DWORD sendCall3 = g_WeChatWinDllAddr + g_WxCalls.sendEmo.call3; + + __asm { + pushad; + pushfd; + mov ebx, dword ptr[sendCall3]; + lea eax, buffer; + push eax; + push 0x0; + sub esp, 0x14; + mov esi, esp; + mov dword ptr [esi], 0x0; + mov dword ptr [esi+0x4], 0x0; + mov dword ptr [esi+0x8], 0x0; + mov dword ptr [esi+0xC], 0x0; + mov dword ptr [esi+0x10], 0x0; + push 0x2; + lea eax, emoWxid; + sub esp, 0x14; + mov ecx, esp; + push eax; + call sendCall1; + sub esp, 0x14; + mov esi, esp; + mov dword ptr [esi], 0x0; + mov dword ptr [esi+0x4], 0x0; + mov dword ptr [esi+0x8], 0x0; + mov dword ptr [esi+0xC], 0x0; + mov dword ptr [esi+0x10], 0x0; + sub esp, 0x14; + mov ecx, esp; + lea eax, emoPath; + push eax; + call sendCall1; + mov ecx, ebx; + call sendCall2; + popfd; + popad; + } +} diff --git a/spy/send_msg.h b/WeChatFerry/spy/send_msg.h similarity index 96% rename from spy/send_msg.h rename to WeChatFerry/spy/send_msg.h index 95039f6..d1d345c 100644 --- a/spy/send_msg.h +++ b/WeChatFerry/spy/send_msg.h @@ -1,11 +1,11 @@ -#pragma once - -#include - -using namespace std; - -void SendTextMessage(string wxid, string msg, string atWxids); -void SendImageMessage(string wxid, string path); -void SendFileMessage(string wxid, string path); -void SendXmlMessage(string receiver, string xml, string path, int type); -void SendEmotionMessage(string wxid, string path); +#pragma once + +#include + +using namespace std; + +void SendTextMessage(string wxid, string msg, string atWxids); +void SendImageMessage(string wxid, string path); +void SendFileMessage(string wxid, string path); +void SendXmlMessage(string receiver, string xml, string path, int type); +void SendEmotionMessage(string wxid, string path); diff --git a/spy/spy.aps b/WeChatFerry/spy/spy.aps similarity index 100% rename from spy/spy.aps rename to WeChatFerry/spy/spy.aps diff --git a/spy/spy.cpp b/WeChatFerry/spy/spy.cpp similarity index 100% rename from spy/spy.cpp rename to WeChatFerry/spy/spy.cpp diff --git a/spy/spy.def b/WeChatFerry/spy/spy.def similarity index 100% rename from spy/spy.def rename to WeChatFerry/spy/spy.def diff --git a/spy/spy.h b/WeChatFerry/spy/spy.h similarity index 100% rename from spy/spy.h rename to WeChatFerry/spy/spy.h diff --git a/spy/spy.rc b/WeChatFerry/spy/spy.rc similarity index 100% rename from spy/spy.rc rename to WeChatFerry/spy/spy.rc diff --git a/spy/spy_types.h b/WeChatFerry/spy/spy_types.h similarity index 95% rename from spy/spy_types.h rename to WeChatFerry/spy/spy_types.h index 89287af..b26d546 100644 --- a/spy/spy_types.h +++ b/WeChatFerry/spy/spy_types.h @@ -1,110 +1,110 @@ -#pragma once - -#include "framework.h" - -typedef struct UserInfoCall { - DWORD wxid; - DWORD nickName; - DWORD mobile; - DWORD home; -} UserInfoCall_t; - -typedef struct RecvMsg { - DWORD hook; // Hook地址 - DWORD call; // Call地址 - DWORD type; // 消息类型地址 - DWORD isSelf; // 是否自己发送标志地址 - DWORD msgId; // 消息ID地址 - DWORD msgXml; // 消息xml内容地址 - DWORD roomId; // 群聊时,为群ID;私聊时,为微信ID - DWORD wxId; // 私聊时,为空;群聊时,为发送者微信ID - DWORD content; // 消息内容地址 - DWORD thumb; // 缩略图 - DWORD extra; // 附加数据 -} RecvMsg_t; - -typedef struct SendText { - DWORD call1; - DWORD call2; - DWORD call3; -} SendText_t; - -typedef struct Sendfile { - DWORD call1; - DWORD call2; - DWORD call3; - DWORD call4; -} Sendfile_t; - -typedef struct Contact { - DWORD base; - DWORD head; - DWORD wxId; - DWORD wxCode; - DWORD wxRemark; - DWORD wxName; - DWORD wxGender; - DWORD wxCountry; - DWORD wxProvince; - DWORD wxCity; -} Contact_t; - -typedef struct Sql { - DWORD exec; - DWORD base; - DWORD start; - DWORD end; - DWORD slot; - DWORD name; -} Sql_t; - -typedef struct NewFriend { - DWORD call1; - DWORD call2; - DWORD call3; - DWORD call4; -} NewFriend_t; - -typedef struct RoomMember { - DWORD call1; - DWORD call2; - DWORD call3; -} RoomMember_t; - -typedef struct Xml { - DWORD call1; - DWORD call2; - DWORD call3; - DWORD call4; - DWORD param; -} Xml_t; - -typedef struct TF { - DWORD call1; - DWORD call2; - DWORD call3; -} TF_t; - -typedef struct WxCalls { - DWORD login; // 登录状态 - UserInfoCall_t ui; // 用户信息 - SendText_t sendText; // 发送消息 - RecvMsg_t recvMsg; // 接收消息 - Sendfile_t sendImg; // 发送图片 - Sendfile_t sendFile; // 发送文件 - Xml_t sendXml; // 发送XML - Sendfile_t sendEmo; // 发送表情 - Contact_t contact; // 获取联系人 - Sql_t sql; // 执行 SQL - NewFriend_t anf; // 通过好友申请 - RoomMember_t arm; // 添加群成员 - RoomMember_t drm; // 删除群成员 - TF_t tf; // 接收转账 -} WxCalls_t; - -typedef struct WxString { - wchar_t *text; - DWORD size; - DWORD capacity; - char fill[8]; -} WxString_t; +#pragma once + +#include "framework.h" + +typedef struct UserInfoCall { + DWORD wxid; + DWORD nickName; + DWORD mobile; + DWORD home; +} UserInfoCall_t; + +typedef struct RecvMsg { + DWORD hook; // Hook地址 + DWORD call; // Call地址 + DWORD type; // 消息类型地址 + DWORD isSelf; // 是否自己发送标志地址 + DWORD msgId; // 消息ID地址 + DWORD msgXml; // 消息xml内容地址 + DWORD roomId; // 群聊时,为群ID;私聊时,为微信ID + DWORD wxId; // 私聊时,为空;群聊时,为发送者微信ID + DWORD content; // 消息内容地址 + DWORD thumb; // 缩略图 + DWORD extra; // 附加数据 +} RecvMsg_t; + +typedef struct SendText { + DWORD call1; + DWORD call2; + DWORD call3; +} SendText_t; + +typedef struct Sendfile { + DWORD call1; + DWORD call2; + DWORD call3; + DWORD call4; +} Sendfile_t; + +typedef struct Contact { + DWORD base; + DWORD head; + DWORD wxId; + DWORD wxCode; + DWORD wxRemark; + DWORD wxName; + DWORD wxGender; + DWORD wxCountry; + DWORD wxProvince; + DWORD wxCity; +} Contact_t; + +typedef struct Sql { + DWORD exec; + DWORD base; + DWORD start; + DWORD end; + DWORD slot; + DWORD name; +} Sql_t; + +typedef struct NewFriend { + DWORD call1; + DWORD call2; + DWORD call3; + DWORD call4; +} NewFriend_t; + +typedef struct RoomMember { + DWORD call1; + DWORD call2; + DWORD call3; +} RoomMember_t; + +typedef struct Xml { + DWORD call1; + DWORD call2; + DWORD call3; + DWORD call4; + DWORD param; +} Xml_t; + +typedef struct TF { + DWORD call1; + DWORD call2; + DWORD call3; +} TF_t; + +typedef struct WxCalls { + DWORD login; // 登录状态 + UserInfoCall_t ui; // 用户信息 + SendText_t sendText; // 发送消息 + RecvMsg_t recvMsg; // 接收消息 + Sendfile_t sendImg; // 发送图片 + Sendfile_t sendFile; // 发送文件 + Xml_t sendXml; // 发送XML + Sendfile_t sendEmo; // 发送表情 + Contact_t contact; // 获取联系人 + Sql_t sql; // 执行 SQL + NewFriend_t anf; // 通过好友申请 + RoomMember_t arm; // 添加群成员 + RoomMember_t drm; // 删除群成员 + TF_t tf; // 接收转账 +} WxCalls_t; + +typedef struct WxString { + wchar_t *text; + DWORD size; + DWORD capacity; + char fill[8]; +} WxString_t; diff --git a/spy/sqlite3.h b/WeChatFerry/spy/sqlite3.h similarity index 100% rename from spy/sqlite3.h rename to WeChatFerry/spy/sqlite3.h diff --git a/spy/user_info.cpp b/WeChatFerry/spy/user_info.cpp similarity index 100% rename from spy/user_info.cpp rename to WeChatFerry/spy/user_info.cpp diff --git a/spy/user_info.h b/WeChatFerry/spy/user_info.h similarity index 100% rename from spy/user_info.h rename to WeChatFerry/spy/user_info.h diff --git a/spy/util.cpp b/WeChatFerry/spy/util.cpp similarity index 100% rename from spy/util.cpp rename to WeChatFerry/spy/util.cpp diff --git a/spy/util.h b/WeChatFerry/spy/util.h similarity index 100% rename from spy/util.h rename to WeChatFerry/spy/util.h diff --git a/wcf/main.cpp b/WeChatFerry/wcf/main.cpp similarity index 100% rename from wcf/main.cpp rename to WeChatFerry/wcf/main.cpp diff --git a/wcf/wcf.vcxproj b/WeChatFerry/wcf/wcf.vcxproj similarity index 98% rename from wcf/wcf.vcxproj rename to WeChatFerry/wcf/wcf.vcxproj index 983bee2..1f9b67f 100644 --- a/wcf/wcf.vcxproj +++ b/WeChatFerry/wcf/wcf.vcxproj @@ -119,7 +119,7 @@ xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)Out -xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)python\wcferry +xcopy /y $(OutDir)$(TargetFileName) $(SolutionDir)..\clients\python\wcferry Copy files diff --git a/wcf/wcf.vcxproj.filters b/WeChatFerry/wcf/wcf.vcxproj.filters similarity index 100% rename from wcf/wcf.vcxproj.filters rename to WeChatFerry/wcf/wcf.vcxproj.filters diff --git a/sdk/SDK.vcxproj.user b/WeChatFerry/wcf/wcf.vcxproj.user similarity index 92% rename from sdk/SDK.vcxproj.user rename to WeChatFerry/wcf/wcf.vcxproj.user index 0f14913..88a5509 100644 --- a/sdk/SDK.vcxproj.user +++ b/WeChatFerry/wcf/wcf.vcxproj.user @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/QR.jpeg b/assets/QR.jpeg similarity index 100% rename from QR.jpeg rename to assets/QR.jpeg diff --git a/TEQuant.jpg b/assets/TEQuant.jpg similarity index 100% rename from TEQuant.jpg rename to assets/TEQuant.jpg diff --git a/demo.gif b/assets/demo.gif similarity index 100% rename from demo.gif rename to assets/demo.gif diff --git a/go/LICENSE b/clients/go/LICENSE similarity index 100% rename from go/LICENSE rename to clients/go/LICENSE diff --git a/go/README.md b/clients/go/README.md similarity index 100% rename from go/README.md rename to clients/go/README.md diff --git a/go/go.mod b/clients/go/go.mod similarity index 100% rename from go/go.mod rename to clients/go/go.mod diff --git a/go/go.sum b/clients/go/go.sum similarity index 100% rename from go/go.sum rename to clients/go/go.sum diff --git a/go/proto/wcf.proto b/clients/go/proto/wcf.proto similarity index 100% rename from go/proto/wcf.proto rename to clients/go/proto/wcf.proto diff --git a/go/wcf/wcf.go b/clients/go/wcf/wcf.go similarity index 100% rename from go/wcf/wcf.go rename to clients/go/wcf/wcf.go diff --git a/go/wcf/wcf.pb.go b/clients/go/wcf/wcf.pb.go similarity index 100% rename from go/wcf/wcf.pb.go rename to clients/go/wcf/wcf.pb.go diff --git a/go/wcf/wcf_test.go b/clients/go/wcf/wcf_test.go similarity index 100% rename from go/wcf/wcf_test.go rename to clients/go/wcf/wcf_test.go diff --git a/http/MANIFEST.in b/clients/http/MANIFEST.in similarity index 100% rename from http/MANIFEST.in rename to clients/http/MANIFEST.in diff --git a/http/README.MD b/clients/http/README.MD similarity index 100% rename from http/README.MD rename to clients/http/README.MD diff --git a/http/setup.py b/clients/http/setup.py similarity index 100% rename from http/setup.py rename to clients/http/setup.py diff --git a/http/wcfhttp/__init__.py b/clients/http/wcfhttp/__init__.py similarity index 100% rename from http/wcfhttp/__init__.py rename to clients/http/wcfhttp/__init__.py diff --git a/http/wcfhttp/core.py b/clients/http/wcfhttp/core.py similarity index 100% rename from http/wcfhttp/core.py rename to clients/http/wcfhttp/core.py diff --git a/http/wcfhttp/main.py b/clients/http/wcfhttp/main.py similarity index 100% rename from http/wcfhttp/main.py rename to clients/http/wcfhttp/main.py diff --git a/java/README.MD b/clients/java/README.MD similarity index 100% rename from java/README.MD rename to clients/java/README.MD diff --git a/java/wcferry/build.gradle b/clients/java/wcferry/build.gradle similarity index 100% rename from java/wcferry/build.gradle rename to clients/java/wcferry/build.gradle diff --git a/java/wcferry/gradle/wrapper/gradle-wrapper.jar b/clients/java/wcferry/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from java/wcferry/gradle/wrapper/gradle-wrapper.jar rename to clients/java/wcferry/gradle/wrapper/gradle-wrapper.jar diff --git a/java/wcferry/gradle/wrapper/gradle-wrapper.properties b/clients/java/wcferry/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from java/wcferry/gradle/wrapper/gradle-wrapper.properties rename to clients/java/wcferry/gradle/wrapper/gradle-wrapper.properties diff --git a/java/wcferry/gradlew b/clients/java/wcferry/gradlew similarity index 100% rename from java/wcferry/gradlew rename to clients/java/wcferry/gradlew diff --git a/java/wcferry/gradlew.bat b/clients/java/wcferry/gradlew.bat similarity index 100% rename from java/wcferry/gradlew.bat rename to clients/java/wcferry/gradlew.bat diff --git a/java/wcferry/libs/nng-java-1.4.0-SNAPSHOT.jar b/clients/java/wcferry/libs/nng-java-1.4.0-SNAPSHOT.jar similarity index 100% rename from java/wcferry/libs/nng-java-1.4.0-SNAPSHOT.jar rename to clients/java/wcferry/libs/nng-java-1.4.0-SNAPSHOT.jar diff --git a/java/wcferry/settings.gradle b/clients/java/wcferry/settings.gradle similarity index 100% rename from java/wcferry/settings.gradle rename to clients/java/wcferry/settings.gradle diff --git a/java/wcferry/src/main/java/com/iamteer/Client.java b/clients/java/wcferry/src/main/java/com/iamteer/Client.java similarity index 100% rename from java/wcferry/src/main/java/com/iamteer/Client.java rename to clients/java/wcferry/src/main/java/com/iamteer/Client.java diff --git a/java/wcferry/src/main/java/com/iamteer/Main.java b/clients/java/wcferry/src/main/java/com/iamteer/Main.java similarity index 100% rename from java/wcferry/src/main/java/com/iamteer/Main.java rename to clients/java/wcferry/src/main/java/com/iamteer/Main.java diff --git a/java/wcferry/src/main/java/com/iamteer/Wcf.java b/clients/java/wcferry/src/main/java/com/iamteer/Wcf.java similarity index 100% rename from java/wcferry/src/main/java/com/iamteer/Wcf.java rename to clients/java/wcferry/src/main/java/com/iamteer/Wcf.java diff --git a/java/wcferry/src/main/resources/logback.xml b/clients/java/wcferry/src/main/resources/logback.xml similarity index 100% rename from java/wcferry/src/main/resources/logback.xml rename to clients/java/wcferry/src/main/resources/logback.xml diff --git a/python/MANIFEST.in b/clients/python/MANIFEST.in similarity index 100% rename from python/MANIFEST.in rename to clients/python/MANIFEST.in diff --git a/python/README.MD b/clients/python/README.MD similarity index 100% rename from python/README.MD rename to clients/python/README.MD diff --git a/python/demo.py b/clients/python/demo.py similarity index 100% rename from python/demo.py rename to clients/python/demo.py diff --git a/python/setup.py b/clients/python/setup.py similarity index 100% rename from python/setup.py rename to clients/python/setup.py diff --git a/python/wcferry/__init__.py b/clients/python/wcferry/__init__.py similarity index 100% rename from python/wcferry/__init__.py rename to clients/python/wcferry/__init__.py diff --git a/python/wcferry/client.py b/clients/python/wcferry/client.py similarity index 100% rename from python/wcferry/client.py rename to clients/python/wcferry/client.py diff --git a/python/wcferry/wcf_pb2.py b/clients/python/wcferry/wcf_pb2.py similarity index 100% rename from python/wcferry/wcf_pb2.py rename to clients/python/wcferry/wcf_pb2.py diff --git a/python/wcferry/wxmsg.py b/clients/python/wcferry/wxmsg.py similarity index 100% rename from python/wcferry/wxmsg.py rename to clients/python/wcferry/wxmsg.py diff --git a/rust/README.MD b/clients/rust/README.MD similarity index 100% rename from rust/README.MD rename to clients/rust/README.MD diff --git a/rust/wcferry/Cargo.toml b/clients/rust/wcferry/Cargo.toml similarity index 100% rename from rust/wcferry/Cargo.toml rename to clients/rust/wcferry/Cargo.toml diff --git a/rust/wcferry/build.rs b/clients/rust/wcferry/build.rs similarity index 100% rename from rust/wcferry/build.rs rename to clients/rust/wcferry/build.rs diff --git a/rust/wcferry/lib/README.MD b/clients/rust/wcferry/lib/README.MD similarity index 100% rename from rust/wcferry/lib/README.MD rename to clients/rust/wcferry/lib/README.MD diff --git a/rust/wcferry/proto/README.MD b/clients/rust/wcferry/proto/README.MD similarity index 100% rename from rust/wcferry/proto/README.MD rename to clients/rust/wcferry/proto/README.MD diff --git a/rust/wcferry/proto/wcf.proto b/clients/rust/wcferry/proto/wcf.proto similarity index 100% rename from rust/wcferry/proto/wcf.proto rename to clients/rust/wcferry/proto/wcf.proto diff --git a/rust/wcferry/src/main.rs b/clients/rust/wcferry/src/main.rs similarity index 100% rename from rust/wcferry/src/main.rs rename to clients/rust/wcferry/src/main.rs diff --git a/rust/wcferry/src/proto/wcf.rs b/clients/rust/wcferry/src/proto/wcf.rs similarity index 100% rename from rust/wcferry/src/proto/wcf.rs rename to clients/rust/wcferry/src/proto/wcf.rs diff --git a/rust/wcferry/src/wechat.rs b/clients/rust/wcferry/src/wechat.rs similarity index 100% rename from rust/wcferry/src/wechat.rs rename to clients/rust/wcferry/src/wechat.rs diff --git a/java/wcferry/src/main/resources/win32-x86-64/nng.dll b/java/wcferry/src/main/resources/win32-x86-64/nng.dll deleted file mode 100644 index 7488b2d..0000000 Binary files a/java/wcferry/src/main/resources/win32-x86-64/nng.dll and /dev/null differ diff --git a/launcher/launcher.rc b/launcher/launcher.rc deleted file mode 100644 index 8af2e2c..0000000 --- a/launcher/launcher.rc +++ /dev/null @@ -1,71 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// (壬й) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) -LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED -#pragma code_page(936) - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_ICON1 ICON "C:\\Projs\\WeChatFerry\\launcher\\icon.ico" - -#endif // (壬й) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED -