mirror of
https://github.com/ttttupup/wxhelper.git
synced 2024-11-22 18:29:23 +08:00
Merge tag '3.9.2.23-v3'
This commit is contained in:
commit
9248d2f91a
1
.gitignore
vendored
1
.gitignore
vendored
@ -32,4 +32,3 @@
|
|||||||
*.app
|
*.app
|
||||||
CMakePresets.json
|
CMakePresets.json
|
||||||
.vscode
|
.vscode
|
||||||
out
|
|
@ -10,13 +10,17 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D '_UNICODE' /D 'UNICODE'")
|
|||||||
file(GLOB CPP_FILES ${PROJECT_SOURCE_DIR}/src/*.cc ${PROJECT_SOURCE_DIR}/src/*.cpp)
|
file(GLOB CPP_FILES ${PROJECT_SOURCE_DIR}/src/*.cc ${PROJECT_SOURCE_DIR}/src/*.cpp)
|
||||||
|
|
||||||
|
|
||||||
include_directories(${VCPKG_INSTALLED_DIR}/x86-windows/include)
|
|
||||||
|
include_directories(c:/soft/vcpkg/installed/x86-windows/include)
|
||||||
|
|
||||||
# add_subdirectory(3rd)
|
# add_subdirectory(3rd)
|
||||||
|
# add_subdirectory(source)
|
||||||
|
|
||||||
find_package(nlohmann_json CONFIG REQUIRED)
|
find_package(nlohmann_json CONFIG REQUIRED)
|
||||||
find_package(unofficial-mongoose CONFIG REQUIRED)
|
find_package(unofficial-mongoose CONFIG REQUIRED)
|
||||||
|
# find_package(spdlog CONFIG REQUIRED)
|
||||||
|
# find_package(minhook CONFIG REQUIRED)
|
||||||
|
|
||||||
|
|
||||||
add_library(wxhelper SHARED ${CPP_FILES} )
|
add_library(wxhelper SHARED ${CPP_FILES} )
|
||||||
|
|
||||||
@ -25,6 +29,8 @@ add_library(wxhelper SHARED ${CPP_FILES} )
|
|||||||
|
|
||||||
target_link_libraries(wxhelper PRIVATE nlohmann_json::nlohmann_json)
|
target_link_libraries(wxhelper PRIVATE nlohmann_json::nlohmann_json)
|
||||||
target_link_libraries(wxhelper PRIVATE unofficial::mongoose::mongoose)
|
target_link_libraries(wxhelper PRIVATE unofficial::mongoose::mongoose)
|
||||||
|
# target_link_libraries(wxhelper PRIVATE spdlog::spdlog spdlog::spdlog_header_only)
|
||||||
|
# target_link_libraries(wxhelper PRIVATE minhook::minhook)
|
||||||
|
|
||||||
SET_TARGET_PROPERTIES(wxhelper PROPERTIES LINKER_LANGUAGE C
|
SET_TARGET_PROPERTIES(wxhelper PROPERTIES LINKER_LANGUAGE C
|
||||||
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
|
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
|
||||||
|
51
python/decrypt.py
Normal file
51
python/decrypt.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import ctypes
|
||||||
|
import hashlib
|
||||||
|
import hmac
|
||||||
|
|
||||||
|
# pip install pycryptodome
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
|
||||||
|
|
||||||
|
def decrypt(password, input_file, out_file):
|
||||||
|
password = bytes.fromhex(password.replace(' ', ''))
|
||||||
|
with open(input_file, 'rb') as (f):
|
||||||
|
blist = f.read()
|
||||||
|
print(len(blist))
|
||||||
|
salt = blist[:16]
|
||||||
|
key = hashlib.pbkdf2_hmac('sha1', password, salt, DEFAULT_ITER, KEY_SIZE)
|
||||||
|
first = blist[16:DEFAULT_PAGESIZE]
|
||||||
|
mac_salt = bytes([x ^ 58 for x in salt])
|
||||||
|
mac_key = hashlib.pbkdf2_hmac('sha1', key, mac_salt, 2, KEY_SIZE)
|
||||||
|
hash_mac = hmac.new(mac_key, digestmod='sha1')
|
||||||
|
hash_mac.update(first[:-32])
|
||||||
|
hash_mac.update(bytes(ctypes.c_int(1)))
|
||||||
|
if hash_mac.digest() == first[-32:-12]:
|
||||||
|
print('decrypt success')
|
||||||
|
else:
|
||||||
|
print('password error')
|
||||||
|
return
|
||||||
|
blist = [blist[i:i + DEFAULT_PAGESIZE] for i in range(DEFAULT_PAGESIZE, len(blist), DEFAULT_PAGESIZE)]
|
||||||
|
with open(out_file, 'wb') as (f):
|
||||||
|
f.write(SQLITE_FILE_HEADER)
|
||||||
|
t = AES.new(key, AES.MODE_CBC, first[-48:-32])
|
||||||
|
f.write(t.decrypt(first[:-48]))
|
||||||
|
f.write(first[-48:])
|
||||||
|
for i in blist:
|
||||||
|
t = AES.new(key, AES.MODE_CBC, i[-48:-32])
|
||||||
|
f.write(t.decrypt(i[:-48]))
|
||||||
|
f.write(i[-48:])
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
password = '565735E30E474DA09250CB5AA047E3940FFA1C6F767C4263B13ABB512933DA49'
|
||||||
|
input_file = 'C:/var/Applet.db'
|
||||||
|
out_file = 'c:/var/out/Applet.db'
|
||||||
|
decrypt(password, input_file, out_file)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
SQLITE_FILE_HEADER = bytes('SQLite format 3', encoding='ASCII') + bytes(1)
|
||||||
|
KEY_SIZE = 32
|
||||||
|
DEFAULT_PAGESIZE = 4096
|
||||||
|
DEFAULT_ITER = 64000
|
||||||
|
main()
|
20
source/CMakeLists.txt
Normal file
20
source/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.0.0)
|
||||||
|
project(ConsoleApplication VERSION 1.0.0)
|
||||||
|
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D '_UNICODE' /D 'UNICODE'")
|
||||||
|
|
||||||
|
file(GLOB INJECT_CPP_FILES ${PROJECT_SOURCE_DIR}/*.cc ${PROJECT_SOURCE_DIR}/*.cpp)
|
||||||
|
|
||||||
|
add_executable (ConsoleApplication ${INJECT_CPP_FILES})
|
||||||
|
|
||||||
|
SET_TARGET_PROPERTIES(ConsoleApplication PROPERTIES LINKER_LANGUAGE C
|
||||||
|
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin
|
||||||
|
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin
|
||||||
|
OUTPUT_NAME "ConsoleApplication"
|
||||||
|
PREFIX "")
|
||||||
|
|
962
source/ConsoleApplication.cc
Normal file
962
source/ConsoleApplication.cc
Normal file
@ -0,0 +1,962 @@
|
|||||||
|
// ConsoleApplication.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
|
||||||
|
// https://github.com/yihleego/handle-tools
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <tlhelp32.h>
|
||||||
|
#include "getopt.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "ntstatus.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
|
||||||
|
|
||||||
|
bool endsWith(const std::string& str, const std::string suffix) {
|
||||||
|
if (suffix.length() > str.length()) { return false; }
|
||||||
|
return (str.rfind(suffix) == (str.length() - suffix.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct _UNICODE_STRING {
|
||||||
|
USHORT Length;
|
||||||
|
USHORT MaximumLength;
|
||||||
|
PWSTR Buffer;
|
||||||
|
} UNICODE_STRING, * PUNICODE_STRING;
|
||||||
|
|
||||||
|
typedef struct _SYSTEM_HANDLE {
|
||||||
|
PVOID Object;
|
||||||
|
HANDLE UniqueProcessId;
|
||||||
|
HANDLE HandleValue;
|
||||||
|
ULONG GrantedAccess;
|
||||||
|
USHORT CreatorBackTraceIndex;
|
||||||
|
USHORT ObjectTypeIndex;
|
||||||
|
ULONG HandleAttributes;
|
||||||
|
ULONG Reserved;
|
||||||
|
} SYSTEM_HANDLE, * PSYSTEM_HANDLE;
|
||||||
|
|
||||||
|
typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
|
||||||
|
ULONG_PTR HandleCount;
|
||||||
|
ULONG_PTR Reserved;
|
||||||
|
SYSTEM_HANDLE Handles[1];
|
||||||
|
} SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX;
|
||||||
|
|
||||||
|
typedef struct _OBJECT_BASIC_INFORMATION {
|
||||||
|
ULONG Attributes;
|
||||||
|
ACCESS_MASK GrantedAccess;
|
||||||
|
ULONG HandleCount;
|
||||||
|
ULONG PointerCount;
|
||||||
|
ULONG PagedPoolCharge;
|
||||||
|
ULONG NonPagedPoolCharge;
|
||||||
|
ULONG Reserved[3];
|
||||||
|
ULONG NameInfoSize;
|
||||||
|
ULONG TypeInfoSize;
|
||||||
|
ULONG SecurityDescriptorSize;
|
||||||
|
LARGE_INTEGER CreationTime;
|
||||||
|
} OBJECT_BASIC_INFORMATION, * POBJECT_BASIC_INFORMATION;
|
||||||
|
|
||||||
|
typedef struct _OBJECT_NAME_INFORMATION {
|
||||||
|
UNICODE_STRING Name;
|
||||||
|
} OBJECT_NAME_INFORMATION, * POBJECT_NAME_INFORMATION;
|
||||||
|
|
||||||
|
typedef struct _OBJECT_TYPE_INFORMATION {
|
||||||
|
UNICODE_STRING TypeName;
|
||||||
|
ULONG Reserved[22]; // reserved for internal use
|
||||||
|
} OBJECT_TYPE_INFORMATION, * POBJECT_TYPE_INFORMATION;
|
||||||
|
|
||||||
|
typedef enum _SYSTEM_INFORMATION_CLASS {
|
||||||
|
SystemBasicInformation, // q: SYSTEM_BASIC_INFORMATION
|
||||||
|
SystemProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION
|
||||||
|
SystemPerformanceInformation, // q: SYSTEM_PERFORMANCE_INFORMATION
|
||||||
|
SystemTimeOfDayInformation, // q: SYSTEM_TIMEOFDAY_INFORMATION
|
||||||
|
SystemPathInformation, // not implemented
|
||||||
|
SystemProcessInformation, // q: SYSTEM_PROCESS_INFORMATION
|
||||||
|
SystemCallCountInformation, // q: SYSTEM_CALL_COUNT_INFORMATION
|
||||||
|
SystemDeviceInformation, // q: SYSTEM_DEVICE_INFORMATION
|
||||||
|
SystemProcessorPerformanceInformation, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
|
||||||
|
SystemFlagsInformation, // q: SYSTEM_FLAGS_INFORMATION
|
||||||
|
SystemCallTimeInformation, // not implemented // SYSTEM_CALL_TIME_INFORMATION // 10
|
||||||
|
SystemModuleInformation, // q: RTL_PROCESS_MODULES
|
||||||
|
SystemLocksInformation, // q: RTL_PROCESS_LOCKS
|
||||||
|
SystemStackTraceInformation, // q: RTL_PROCESS_BACKTRACES
|
||||||
|
SystemPagedPoolInformation, // not implemented
|
||||||
|
SystemNonPagedPoolInformation, // not implemented
|
||||||
|
SystemHandleInformation, // q: SYSTEM_HANDLE_INFORMATION
|
||||||
|
SystemObjectInformation, // q: SYSTEM_OBJECTTYPE_INFORMATION mixed with SYSTEM_OBJECT_INFORMATION
|
||||||
|
SystemPageFileInformation, // q: SYSTEM_PAGEFILE_INFORMATION
|
||||||
|
SystemVdmInstemulInformation, // q: SYSTEM_VDM_INSTEMUL_INFO
|
||||||
|
SystemVdmBopInformation, // not implemented // 20
|
||||||
|
SystemFileCacheInformation, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemCache)
|
||||||
|
SystemPoolTagInformation, // q: SYSTEM_POOLTAG_INFORMATION
|
||||||
|
SystemInterruptInformation, // q: SYSTEM_INTERRUPT_INFORMATION
|
||||||
|
SystemDpcBehaviorInformation, // q: SYSTEM_DPC_BEHAVIOR_INFORMATION; s: SYSTEM_DPC_BEHAVIOR_INFORMATION (requires SeLoadDriverPrivilege)
|
||||||
|
SystemFullMemoryInformation, // not implemented // SYSTEM_MEMORY_USAGE_INFORMATION
|
||||||
|
SystemLoadGdiDriverInformation, // s (kernel-mode only)
|
||||||
|
SystemUnloadGdiDriverInformation, // s (kernel-mode only)
|
||||||
|
SystemTimeAdjustmentInformation, // q: SYSTEM_QUERY_TIME_ADJUST_INFORMATION; s: SYSTEM_SET_TIME_ADJUST_INFORMATION (requires SeSystemtimePrivilege)
|
||||||
|
SystemSummaryMemoryInformation, // not implemented // SYSTEM_MEMORY_USAGE_INFORMATION
|
||||||
|
SystemMirrorMemoryInformation, // s (requires license value "Kernel-MemoryMirroringSupported") (requires SeShutdownPrivilege) // 30
|
||||||
|
SystemPerformanceTraceInformation, // q; s: (type depends on EVENT_TRACE_INFORMATION_CLASS)
|
||||||
|
SystemObsolete0, // not implemented
|
||||||
|
SystemExceptionInformation, // q: SYSTEM_EXCEPTION_INFORMATION
|
||||||
|
SystemCrashDumpStateInformation, // s: SYSTEM_CRASH_DUMP_STATE_INFORMATION (requires SeDebugPrivilege)
|
||||||
|
SystemKernelDebuggerInformation, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION
|
||||||
|
SystemContextSwitchInformation, // q: SYSTEM_CONTEXT_SWITCH_INFORMATION
|
||||||
|
SystemRegistryQuotaInformation, // q: SYSTEM_REGISTRY_QUOTA_INFORMATION; s (requires SeIncreaseQuotaPrivilege)
|
||||||
|
SystemExtendServiceTableInformation, // s (requires SeLoadDriverPrivilege) // loads win32k only
|
||||||
|
SystemPrioritySeperation, // s (requires SeTcbPrivilege)
|
||||||
|
SystemVerifierAddDriverInformation, // s (requires SeDebugPrivilege) // 40
|
||||||
|
SystemVerifierRemoveDriverInformation, // s (requires SeDebugPrivilege)
|
||||||
|
SystemProcessorIdleInformation, // q: SYSTEM_PROCESSOR_IDLE_INFORMATION
|
||||||
|
SystemLegacyDriverInformation, // q: SYSTEM_LEGACY_DRIVER_INFORMATION
|
||||||
|
SystemCurrentTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION
|
||||||
|
SystemLookasideInformation, // q: SYSTEM_LOOKASIDE_INFORMATION
|
||||||
|
SystemTimeSlipNotification, // s: HANDLE (NtCreateEvent) (requires SeSystemtimePrivilege)
|
||||||
|
SystemSessionCreate, // not implemented
|
||||||
|
SystemSessionDetach, // not implemented
|
||||||
|
SystemSessionInformation, // not implemented (SYSTEM_SESSION_INFORMATION)
|
||||||
|
SystemRangeStartInformation, // q: SYSTEM_RANGE_START_INFORMATION // 50
|
||||||
|
SystemVerifierInformation, // q: SYSTEM_VERIFIER_INFORMATION; s (requires SeDebugPrivilege)
|
||||||
|
SystemVerifierThunkExtend, // s (kernel-mode only)
|
||||||
|
SystemSessionProcessInformation, // q: SYSTEM_SESSION_PROCESS_INFORMATION
|
||||||
|
SystemLoadGdiDriverInSystemSpace, // s: SYSTEM_GDI_DRIVER_INFORMATION (kernel-mode only) (same as SystemLoadGdiDriverInformation)
|
||||||
|
SystemNumaProcessorMap, // q: SYSTEM_NUMA_INFORMATION
|
||||||
|
SystemPrefetcherInformation, // q; s: PREFETCHER_INFORMATION // PfSnQueryPrefetcherInformation
|
||||||
|
SystemExtendedProcessInformation, // q: SYSTEM_PROCESS_INFORMATION
|
||||||
|
SystemRecommendedSharedDataAlignment, // q: ULONG // KeGetRecommendedSharedDataAlignment
|
||||||
|
SystemComPlusPackage, // q; s: ULONG
|
||||||
|
SystemNumaAvailableMemory, // q: SYSTEM_NUMA_INFORMATION // 60
|
||||||
|
SystemProcessorPowerInformation, // q: SYSTEM_PROCESSOR_POWER_INFORMATION
|
||||||
|
SystemEmulationBasicInformation, // q: SYSTEM_BASIC_INFORMATION
|
||||||
|
SystemEmulationProcessorInformation, // q: SYSTEM_PROCESSOR_INFORMATION
|
||||||
|
SystemExtendedHandleInformation, // q: SYSTEM_HANDLE_INFORMATION_EX
|
||||||
|
SystemLostDelayedWriteInformation, // q: ULONG
|
||||||
|
SystemBigPoolInformation, // q: SYSTEM_BIGPOOL_INFORMATION
|
||||||
|
SystemSessionPoolTagInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION
|
||||||
|
SystemSessionMappedViewInformation, // q: SYSTEM_SESSION_MAPPED_VIEW_INFORMATION
|
||||||
|
SystemHotpatchInformation, // q; s: SYSTEM_HOTPATCH_CODE_INFORMATION
|
||||||
|
SystemObjectSecurityMode, // q: ULONG // 70
|
||||||
|
SystemWatchdogTimerHandler, // s: SYSTEM_WATCHDOG_HANDLER_INFORMATION // (kernel-mode only)
|
||||||
|
SystemWatchdogTimerInformation, // q: SYSTEM_WATCHDOG_TIMER_INFORMATION // (kernel-mode only)
|
||||||
|
SystemLogicalProcessorInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION
|
||||||
|
SystemWow64SharedInformationObsolete, // not implemented
|
||||||
|
SystemRegisterFirmwareTableInformationHandler, // s: SYSTEM_FIRMWARE_TABLE_HANDLER // (kernel-mode only)
|
||||||
|
SystemFirmwareTableInformation, // SYSTEM_FIRMWARE_TABLE_INFORMATION
|
||||||
|
SystemModuleInformationEx, // q: RTL_PROCESS_MODULE_INFORMATION_EX
|
||||||
|
SystemVerifierTriageInformation, // not implemented
|
||||||
|
SystemSuperfetchInformation, // q; s: SUPERFETCH_INFORMATION // PfQuerySuperfetchInformation
|
||||||
|
SystemMemoryListInformation, // q: SYSTEM_MEMORY_LIST_INFORMATION; s: SYSTEM_MEMORY_LIST_COMMAND (requires SeProfileSingleProcessPrivilege) // 80
|
||||||
|
SystemFileCacheInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (same as SystemFileCacheInformation)
|
||||||
|
SystemThreadPriorityClientIdInformation, // s: SYSTEM_THREAD_CID_PRIORITY_INFORMATION (requires SeIncreaseBasePriorityPrivilege)
|
||||||
|
SystemProcessorIdleCycleTimeInformation, // q: SYSTEM_PROCESSOR_IDLE_CYCLE_TIME_INFORMATION[]
|
||||||
|
SystemVerifierCancellationInformation, // SYSTEM_VERIFIER_CANCELLATION_INFORMATION // name:wow64:whNT32QuerySystemVerifierCancellationInformation
|
||||||
|
SystemProcessorPowerInformationEx, // not implemented
|
||||||
|
SystemRefTraceInformation, // q; s: SYSTEM_REF_TRACE_INFORMATION // ObQueryRefTraceInformation
|
||||||
|
SystemSpecialPoolInformation, // q; s: SYSTEM_SPECIAL_POOL_INFORMATION (requires SeDebugPrivilege) // MmSpecialPoolTag, then MmSpecialPoolCatchOverruns != 0
|
||||||
|
SystemProcessIdInformation, // q: SYSTEM_PROCESS_ID_INFORMATION
|
||||||
|
SystemErrorPortInformation, // s (requires SeTcbPrivilege)
|
||||||
|
SystemBootEnvironmentInformation, // q: SYSTEM_BOOT_ENVIRONMENT_INFORMATION // 90
|
||||||
|
SystemHypervisorInformation, // q: SYSTEM_HYPERVISOR_QUERY_INFORMATION
|
||||||
|
SystemVerifierInformationEx, // q; s: SYSTEM_VERIFIER_INFORMATION_EX
|
||||||
|
SystemTimeZoneInformation, // q; s: RTL_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege)
|
||||||
|
SystemImageFileExecutionOptionsInformation, // s: SYSTEM_IMAGE_FILE_EXECUTION_OPTIONS_INFORMATION (requires SeTcbPrivilege)
|
||||||
|
SystemCoverageInformation, // q: COVERAGE_MODULES s: COVERAGE_MODULE_REQUEST // ExpCovQueryInformation (requires SeDebugPrivilege)
|
||||||
|
SystemPrefetchPatchInformation, // SYSTEM_PREFETCH_PATCH_INFORMATION
|
||||||
|
SystemVerifierFaultsInformation, // s: SYSTEM_VERIFIER_FAULTS_INFORMATION (requires SeDebugPrivilege)
|
||||||
|
SystemSystemPartitionInformation, // q: SYSTEM_SYSTEM_PARTITION_INFORMATION
|
||||||
|
SystemSystemDiskInformation, // q: SYSTEM_SYSTEM_DISK_INFORMATION
|
||||||
|
SystemProcessorPerformanceDistribution, // q: SYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION // 100
|
||||||
|
SystemNumaProximityNodeInformation, // q; s: SYSTEM_NUMA_PROXIMITY_MAP
|
||||||
|
SystemDynamicTimeZoneInformation, // q; s: RTL_DYNAMIC_TIME_ZONE_INFORMATION (requires SeTimeZonePrivilege)
|
||||||
|
SystemCodeIntegrityInformation, // q: SYSTEM_CODEINTEGRITY_INFORMATION // SeCodeIntegrityQueryInformation
|
||||||
|
SystemProcessorMicrocodeUpdateInformation, // s: SYSTEM_PROCESSOR_MICROCODE_UPDATE_INFORMATION
|
||||||
|
SystemProcessorBrandString, // q: CHAR[] // HaliQuerySystemInformation -> HalpGetProcessorBrandString, info class 23
|
||||||
|
SystemVirtualAddressInformation, // q: SYSTEM_VA_LIST_INFORMATION[]; s: SYSTEM_VA_LIST_INFORMATION[] (requires SeIncreaseQuotaPrivilege) // MmQuerySystemVaInformation
|
||||||
|
SystemLogicalProcessorAndGroupInformation, // q: SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX // since WIN7 // KeQueryLogicalProcessorRelationship
|
||||||
|
SystemProcessorCycleTimeInformation, // q: SYSTEM_PROCESSOR_CYCLE_TIME_INFORMATION[]
|
||||||
|
SystemStoreInformation, // q; s: SYSTEM_STORE_INFORMATION (requires SeProfileSingleProcessPrivilege) // SmQueryStoreInformation
|
||||||
|
SystemRegistryAppendString, // s: SYSTEM_REGISTRY_APPEND_STRING_PARAMETERS // 110
|
||||||
|
SystemAitSamplingValue, // s: ULONG (requires SeProfileSingleProcessPrivilege)
|
||||||
|
SystemVhdBootInformation, // q: SYSTEM_VHD_BOOT_INFORMATION
|
||||||
|
SystemCpuQuotaInformation, // q; s: PS_CPU_QUOTA_QUERY_INFORMATION
|
||||||
|
SystemNativeBasicInformation, // q: SYSTEM_BASIC_INFORMATION
|
||||||
|
SystemErrorPortTimeouts, // SYSTEM_ERROR_PORT_TIMEOUTS
|
||||||
|
SystemLowPriorityIoInformation, // q: SYSTEM_LOW_PRIORITY_IO_INFORMATION
|
||||||
|
SystemTpmBootEntropyInformation, // q: TPM_BOOT_ENTROPY_NT_RESULT // ExQueryTpmBootEntropyInformation
|
||||||
|
SystemVerifierCountersInformation, // q: SYSTEM_VERIFIER_COUNTERS_INFORMATION
|
||||||
|
SystemPagedPoolInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypePagedPool)
|
||||||
|
SystemSystemPtesInformationEx, // q: SYSTEM_FILECACHE_INFORMATION; s (requires SeIncreaseQuotaPrivilege) (info for WorkingSetTypeSystemPtes) // 120
|
||||||
|
SystemNodeDistanceInformation,
|
||||||
|
SystemAcpiAuditInformation, // q: SYSTEM_ACPI_AUDIT_INFORMATION // HaliQuerySystemInformation -> HalpAuditQueryResults, info class 26
|
||||||
|
SystemBasicPerformanceInformation, // q: SYSTEM_BASIC_PERFORMANCE_INFORMATION // name:wow64:whNtQuerySystemInformation_SystemBasicPerformanceInformation
|
||||||
|
SystemQueryPerformanceCounterInformation, // q: SYSTEM_QUERY_PERFORMANCE_COUNTER_INFORMATION // since WIN7 SP1
|
||||||
|
SystemSessionBigPoolInformation, // q: SYSTEM_SESSION_POOLTAG_INFORMATION // since WIN8
|
||||||
|
SystemBootGraphicsInformation, // q; s: SYSTEM_BOOT_GRAPHICS_INFORMATION (kernel-mode only)
|
||||||
|
SystemScrubPhysicalMemoryInformation, // q; s: MEMORY_SCRUB_INFORMATION
|
||||||
|
SystemBadPageInformation,
|
||||||
|
SystemProcessorProfileControlArea, // q; s: SYSTEM_PROCESSOR_PROFILE_CONTROL_AREA
|
||||||
|
SystemCombinePhysicalMemoryInformation, // s: MEMORY_COMBINE_INFORMATION, MEMORY_COMBINE_INFORMATION_EX, MEMORY_COMBINE_INFORMATION_EX2 // 130
|
||||||
|
SystemEntropyInterruptTimingInformation, // q; s: SYSTEM_ENTROPY_TIMING_INFORMATION
|
||||||
|
SystemConsoleInformation, // q: SYSTEM_CONSOLE_INFORMATION
|
||||||
|
SystemPlatformBinaryInformation, // q: SYSTEM_PLATFORM_BINARY_INFORMATION (requires SeTcbPrivilege)
|
||||||
|
SystemPolicyInformation, // q: SYSTEM_POLICY_INFORMATION
|
||||||
|
SystemHypervisorProcessorCountInformation, // q: SYSTEM_HYPERVISOR_PROCESSOR_COUNT_INFORMATION
|
||||||
|
SystemDeviceDataInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION
|
||||||
|
SystemDeviceDataEnumerationInformation, // q: SYSTEM_DEVICE_DATA_INFORMATION
|
||||||
|
SystemMemoryTopologyInformation, // q: SYSTEM_MEMORY_TOPOLOGY_INFORMATION
|
||||||
|
SystemMemoryChannelInformation, // q: SYSTEM_MEMORY_CHANNEL_INFORMATION
|
||||||
|
SystemBootLogoInformation, // q: SYSTEM_BOOT_LOGO_INFORMATION // 140
|
||||||
|
SystemProcessorPerformanceInformationEx, // q: SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION_EX // since WINBLUE
|
||||||
|
SystemCriticalProcessErrorLogInformation,
|
||||||
|
SystemSecureBootPolicyInformation, // q: SYSTEM_SECUREBOOT_POLICY_INFORMATION
|
||||||
|
SystemPageFileInformationEx, // q: SYSTEM_PAGEFILE_INFORMATION_EX
|
||||||
|
SystemSecureBootInformation, // q: SYSTEM_SECUREBOOT_INFORMATION
|
||||||
|
SystemEntropyInterruptTimingRawInformation,
|
||||||
|
SystemPortableWorkspaceEfiLauncherInformation, // q: SYSTEM_PORTABLE_WORKSPACE_EFI_LAUNCHER_INFORMATION
|
||||||
|
SystemFullProcessInformation, // q: SYSTEM_PROCESS_INFORMATION with SYSTEM_PROCESS_INFORMATION_EXTENSION (requires admin)
|
||||||
|
SystemKernelDebuggerInformationEx, // q: SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX
|
||||||
|
SystemBootMetadataInformation, // 150
|
||||||
|
SystemSoftRebootInformation, // q: ULONG
|
||||||
|
SystemElamCertificateInformation, // s: SYSTEM_ELAM_CERTIFICATE_INFORMATION
|
||||||
|
SystemOfflineDumpConfigInformation, // q: OFFLINE_CRASHDUMP_CONFIGURATION_TABLE_V2
|
||||||
|
SystemProcessorFeaturesInformation, // q: SYSTEM_PROCESSOR_FEATURES_INFORMATION
|
||||||
|
SystemRegistryReconciliationInformation, // s: NULL (requires admin) (flushes registry hives)
|
||||||
|
SystemEdidInformation, // q: SYSTEM_EDID_INFORMATION
|
||||||
|
SystemManufacturingInformation, // q: SYSTEM_MANUFACTURING_INFORMATION // since THRESHOLD
|
||||||
|
SystemEnergyEstimationConfigInformation, // q: SYSTEM_ENERGY_ESTIMATION_CONFIG_INFORMATION
|
||||||
|
SystemHypervisorDetailInformation, // q: SYSTEM_HYPERVISOR_DETAIL_INFORMATION
|
||||||
|
SystemProcessorCycleStatsInformation, // q: SYSTEM_PROCESSOR_CYCLE_STATS_INFORMATION // 160
|
||||||
|
SystemVmGenerationCountInformation,
|
||||||
|
SystemTrustedPlatformModuleInformation, // q: SYSTEM_TPM_INFORMATION
|
||||||
|
SystemKernelDebuggerFlags, // SYSTEM_KERNEL_DEBUGGER_FLAGS
|
||||||
|
SystemCodeIntegrityPolicyInformation, // q: SYSTEM_CODEINTEGRITYPOLICY_INFORMATION
|
||||||
|
SystemIsolatedUserModeInformation, // q: SYSTEM_ISOLATED_USER_MODE_INFORMATION
|
||||||
|
SystemHardwareSecurityTestInterfaceResultsInformation,
|
||||||
|
SystemSingleModuleInformation, // q: SYSTEM_SINGLE_MODULE_INFORMATION
|
||||||
|
SystemAllowedCpuSetsInformation,
|
||||||
|
SystemVsmProtectionInformation, // q: SYSTEM_VSM_PROTECTION_INFORMATION (previously SystemDmaProtectionInformation)
|
||||||
|
SystemInterruptCpuSetsInformation, // q: SYSTEM_INTERRUPT_CPU_SET_INFORMATION // 170
|
||||||
|
SystemSecureBootPolicyFullInformation, // q: SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION
|
||||||
|
SystemCodeIntegrityPolicyFullInformation,
|
||||||
|
SystemAffinitizedInterruptProcessorInformation, // (requires SeIncreaseBasePriorityPrivilege)
|
||||||
|
SystemRootSiloInformation, // q: SYSTEM_ROOT_SILO_INFORMATION
|
||||||
|
SystemCpuSetInformation, // q: SYSTEM_CPU_SET_INFORMATION // since THRESHOLD2
|
||||||
|
SystemCpuSetTagInformation, // q: SYSTEM_CPU_SET_TAG_INFORMATION
|
||||||
|
SystemWin32WerStartCallout,
|
||||||
|
SystemSecureKernelProfileInformation, // q: SYSTEM_SECURE_KERNEL_HYPERGUARD_PROFILE_INFORMATION
|
||||||
|
SystemCodeIntegrityPlatformManifestInformation, // q: SYSTEM_SECUREBOOT_PLATFORM_MANIFEST_INFORMATION // since REDSTONE
|
||||||
|
SystemInterruptSteeringInformation, // SYSTEM_INTERRUPT_STEERING_INFORMATION_INPUT // 180
|
||||||
|
SystemSupportedProcessorArchitectures, // in: HANDLE, out: SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION[] (Max 5 structs) // NtQuerySystemInformationEx
|
||||||
|
SystemMemoryUsageInformation, // q: SYSTEM_MEMORY_USAGE_INFORMATION
|
||||||
|
SystemCodeIntegrityCertificateInformation, // q: SYSTEM_CODEINTEGRITY_CERTIFICATE_INFORMATION
|
||||||
|
SystemPhysicalMemoryInformation, // q: SYSTEM_PHYSICAL_MEMORY_INFORMATION // since REDSTONE2
|
||||||
|
SystemControlFlowTransition,
|
||||||
|
SystemKernelDebuggingAllowed, // s: ULONG
|
||||||
|
SystemActivityModerationExeState, // SYSTEM_ACTIVITY_MODERATION_EXE_STATE
|
||||||
|
SystemActivityModerationUserSettings, // SYSTEM_ACTIVITY_MODERATION_USER_SETTINGS
|
||||||
|
SystemCodeIntegrityPoliciesFullInformation,
|
||||||
|
SystemCodeIntegrityUnlockInformation, // SYSTEM_CODEINTEGRITY_UNLOCK_INFORMATION // 190
|
||||||
|
SystemIntegrityQuotaInformation,
|
||||||
|
SystemFlushInformation, // q: SYSTEM_FLUSH_INFORMATION
|
||||||
|
SystemProcessorIdleMaskInformation, // q: ULONG_PTR // since REDSTONE3
|
||||||
|
SystemSecureDumpEncryptionInformation,
|
||||||
|
SystemWriteConstraintInformation, // SYSTEM_WRITE_CONSTRAINT_INFORMATION
|
||||||
|
SystemKernelVaShadowInformation, // SYSTEM_KERNEL_VA_SHADOW_INFORMATION
|
||||||
|
SystemHypervisorSharedPageInformation, // SYSTEM_HYPERVISOR_SHARED_PAGE_INFORMATION // since REDSTONE4
|
||||||
|
SystemFirmwareBootPerformanceInformation,
|
||||||
|
SystemCodeIntegrityVerificationInformation, // SYSTEM_CODEINTEGRITYVERIFICATION_INFORMATION
|
||||||
|
SystemFirmwarePartitionInformation, // SYSTEM_FIRMWARE_PARTITION_INFORMATION // 200
|
||||||
|
SystemSpeculationControlInformation, // SYSTEM_SPECULATION_CONTROL_INFORMATION // (CVE-2017-5715) REDSTONE3 and above.
|
||||||
|
SystemDmaGuardPolicyInformation, // SYSTEM_DMA_GUARD_POLICY_INFORMATION
|
||||||
|
SystemEnclaveLaunchControlInformation, // SYSTEM_ENCLAVE_LAUNCH_CONTROL_INFORMATION
|
||||||
|
SystemWorkloadAllowedCpuSetsInformation, // SYSTEM_WORKLOAD_ALLOWED_CPU_SET_INFORMATION // since REDSTONE5
|
||||||
|
SystemCodeIntegrityUnlockModeInformation,
|
||||||
|
SystemLeapSecondInformation, // SYSTEM_LEAP_SECOND_INFORMATION
|
||||||
|
SystemFlags2Information, // q: SYSTEM_FLAGS_INFORMATION
|
||||||
|
SystemSecurityModelInformation, // SYSTEM_SECURITY_MODEL_INFORMATION // since 19H1
|
||||||
|
SystemCodeIntegritySyntheticCacheInformation,
|
||||||
|
SystemFeatureConfigurationInformation, // SYSTEM_FEATURE_CONFIGURATION_INFORMATION // since 20H1 // 210
|
||||||
|
SystemFeatureConfigurationSectionInformation, // SYSTEM_FEATURE_CONFIGURATION_SECTIONS_INFORMATION
|
||||||
|
SystemFeatureUsageSubscriptionInformation, // SYSTEM_FEATURE_USAGE_SUBSCRIPTION_DETAILS
|
||||||
|
SystemSecureSpeculationControlInformation, // SECURE_SPECULATION_CONTROL_INFORMATION
|
||||||
|
SystemSpacesBootInformation, // since 20H2
|
||||||
|
SystemFwRamdiskInformation, // SYSTEM_FIRMWARE_RAMDISK_INFORMATION
|
||||||
|
SystemWheaIpmiHardwareInformation,
|
||||||
|
SystemDifSetRuleClassInformation,
|
||||||
|
SystemDifClearRuleClassInformation,
|
||||||
|
SystemDifApplyPluginVerificationOnDriver,
|
||||||
|
SystemDifRemovePluginVerificationOnDriver, // 220
|
||||||
|
SystemShadowStackInformation, // SYSTEM_SHADOW_STACK_INFORMATION
|
||||||
|
SystemBuildVersionInformation, // SYSTEM_BUILD_VERSION_INFORMATION
|
||||||
|
SystemPoolLimitInformation, // SYSTEM_POOL_LIMIT_INFORMATION
|
||||||
|
SystemCodeIntegrityAddDynamicStore,
|
||||||
|
SystemCodeIntegrityClearDynamicStores,
|
||||||
|
SystemDifPoolTrackingInformation,
|
||||||
|
SystemPoolZeroingInformation, // SYSTEM_POOL_ZEROING_INFORMATION
|
||||||
|
MaxSystemInfoClass
|
||||||
|
} SYSTEM_INFORMATION_CLASS;
|
||||||
|
|
||||||
|
typedef enum _OBJECT_INFORMATION_CLASS {
|
||||||
|
ObjectBasicInformation = 0, // q: OBJECT_BASIC_INFORMATION
|
||||||
|
ObjectNameInformation = 1, // q: OBJECT_NAME_INFORMATION
|
||||||
|
ObjectTypeInformation = 2, // q: OBJECT_TYPE_INFORMATION
|
||||||
|
ObjectTypesInformation, // q: OBJECT_TYPES_INFORMATION
|
||||||
|
ObjectHandleFlagInformation, // qs: OBJECT_HANDLE_FLAG_INFORMATION
|
||||||
|
ObjectSessionInformation, // s: void // change object session // (requires SeTcbPrivilege)
|
||||||
|
ObjectSessionObjectInformation, // s: void // change object session // (requires SeTcbPrivilege)
|
||||||
|
MaxObjectInfoClass
|
||||||
|
} OBJECT_INFORMATION_CLASS;
|
||||||
|
|
||||||
|
typedef NTSTATUS(WINAPI* PNtQuerySystemInformation)(
|
||||||
|
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||||
|
_Inout_ PVOID SystemInformation,
|
||||||
|
_In_ ULONG SystemInformationLength,
|
||||||
|
_Out_opt_ PULONG ReturnLength
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef NTSTATUS(WINAPI* PNtQueryObject)(
|
||||||
|
_In_opt_ HANDLE Handle,
|
||||||
|
_In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,
|
||||||
|
_Out_opt_ PVOID ObjectInformation,
|
||||||
|
_In_ ULONG ObjectInformationLength,
|
||||||
|
_Out_opt_ PULONG ReturnLength);
|
||||||
|
|
||||||
|
typedef NTSTATUS(WINAPI* PNtDuplicateObject)(
|
||||||
|
_In_ HANDLE SourceProcessHandle,
|
||||||
|
_In_ HANDLE SourceHandle,
|
||||||
|
_In_opt_ HANDLE TargetProcessHandle,
|
||||||
|
_Out_opt_ PHANDLE TargetHandle,
|
||||||
|
_In_ ACCESS_MASK DesiredAccess,
|
||||||
|
_In_ ULONG HandleAttributes,
|
||||||
|
_In_ ULONG Options
|
||||||
|
);
|
||||||
|
|
||||||
|
int FindHandles(ULONG pid, LPSTR handleName, BOOL closeHandle, BOOL suffix) {
|
||||||
|
HMODULE ntdll = GetModuleHandle(TEXT("ntdll.dll"));
|
||||||
|
if (NULL == ntdll) {
|
||||||
|
printf("Failed to load 'ntdll.dll'\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
PNtQuerySystemInformation pQuerySystemInformation = (PNtQuerySystemInformation)GetProcAddress(ntdll, "NtQuerySystemInformation");
|
||||||
|
PNtQueryObject pQueryObject = (PNtQueryObject)GetProcAddress(ntdll, "NtQueryObject");
|
||||||
|
PNtDuplicateObject pDuplicateObject = (PNtDuplicateObject)GetProcAddress(ntdll, "NtDuplicateObject");
|
||||||
|
if (NULL == pQuerySystemInformation || NULL == pQueryObject || NULL == pDuplicateObject) {
|
||||||
|
printf("Failed to call 'GetProcAddress()'\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG len = 0x10000;
|
||||||
|
NTSTATUS status;
|
||||||
|
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
|
||||||
|
do {
|
||||||
|
if (len > 0x4000000) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
len *= 2;
|
||||||
|
pHandleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)GlobalAlloc(GMEM_ZEROINIT, len);
|
||||||
|
status = pQuerySystemInformation(SystemExtendedHandleInformation, pHandleInfo, len, &len);
|
||||||
|
} while (status == STATUS_INFO_LENGTH_MISMATCH);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
printf("Failed to call 'NtQuerySystemInformation()' with error code 0x%X\n", status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE currentProcess = GetCurrentProcess();
|
||||||
|
for (int i = 0; i < pHandleInfo->HandleCount; i++) {
|
||||||
|
SYSTEM_HANDLE handle = pHandleInfo->Handles[i];
|
||||||
|
PVOID object = handle.Object;
|
||||||
|
HANDLE handleValue = handle.HandleValue;
|
||||||
|
HANDLE uniqueProcessId = handle.UniqueProcessId;
|
||||||
|
if (NULL != pid && HandleToLong(uniqueProcessId) != pid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
LPSTR pName = NULL;
|
||||||
|
LPSTR pType = NULL;
|
||||||
|
HANDLE sourceProcess = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_DUP_HANDLE | PROCESS_SUSPEND_RESUME, FALSE, HandleToULong(uniqueProcessId));
|
||||||
|
HANDLE targetHandle = NULL;
|
||||||
|
NTSTATUS status = pDuplicateObject(sourceProcess, handleValue, currentProcess, &targetHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||||
|
if (NT_SUCCESS(status)) {
|
||||||
|
//printf("Failed to call 'NtDuplicateObject()' with error code 0x%X\n", status);
|
||||||
|
POBJECT_NAME_INFORMATION pNameInfo = (POBJECT_NAME_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len);
|
||||||
|
POBJECT_TYPE_INFORMATION pTypeInfo = (POBJECT_TYPE_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len);
|
||||||
|
if (NT_SUCCESS(pQueryObject(targetHandle, ObjectNameInformation, pNameInfo, len, NULL))) {
|
||||||
|
pName = (LPSTR)GlobalAlloc(GMEM_ZEROINIT, pNameInfo->Name.Length);
|
||||||
|
WideCharToMultiByte(CP_ACP, 0, pNameInfo->Name.Buffer, -1, pName, pNameInfo->Name.Length, NULL, NULL);
|
||||||
|
}
|
||||||
|
if (NT_SUCCESS(pQueryObject(targetHandle, ObjectTypeInformation, pTypeInfo, len, NULL))) {
|
||||||
|
pType = (LPSTR)GlobalAlloc(GMEM_ZEROINIT, pTypeInfo->TypeName.Length);
|
||||||
|
WideCharToMultiByte(CP_ACP, 0, pTypeInfo->TypeName.Buffer, -1, pType, pTypeInfo->TypeName.Length, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (NULL != handleName) {
|
||||||
|
if (suffix) {
|
||||||
|
if (NULL == pName || !endsWith(std::string(pName), std::string(handleName))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (NULL == pName || 0 != strcmp(pName, handleName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TRUE == closeHandle) {
|
||||||
|
HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, HandleToLong(uniqueProcessId));
|
||||||
|
DuplicateHandle(hProcess, handleValue, 0, 0, 0, 0, DUPLICATE_CLOSE_SOURCE);
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("PID: %-6d\t", uniqueProcessId);
|
||||||
|
printf("Handle: 0x%-3x\t", handleValue);
|
||||||
|
printf("Object: 0x%-8X\t", object);
|
||||||
|
printf("Type: %-20s\t", NULL != pType ? pType : "<Unknown type>");
|
||||||
|
printf("Name: %-30s\t", NULL != pName ? pName : "");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DisplayHandles() {
|
||||||
|
return FindHandles(NULL, NULL, FALSE, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int DisplayHandles(ULONG pid) {
|
||||||
|
return FindHandles(pid, NULL, FALSE, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FindHandle(ULONG pid, LPSTR handleName) {
|
||||||
|
return FindHandles(pid, handleName, FALSE, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CloseHandle(ULONG pid, LPSTR handleName) {
|
||||||
|
return FindHandles(pid, handleName, TRUE, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE FindHandleByName(ULONG pid, LPSTR handleName) {
|
||||||
|
HMODULE ntdll = GetModuleHandle(TEXT("ntdll.dll"));
|
||||||
|
if (NULL == ntdll) {
|
||||||
|
printf("Failed to load 'ntdll.dll'\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
PNtQuerySystemInformation pQuerySystemInformation = (PNtQuerySystemInformation)GetProcAddress(ntdll, "NtQuerySystemInformation");
|
||||||
|
PNtQueryObject pQueryObject = (PNtQueryObject)GetProcAddress(ntdll, "NtQueryObject");
|
||||||
|
PNtDuplicateObject pDuplicateObject = (PNtDuplicateObject)GetProcAddress(ntdll, "NtDuplicateObject");
|
||||||
|
if (NULL == pQuerySystemInformation || NULL == pQueryObject || NULL == pDuplicateObject) {
|
||||||
|
printf("Failed to call 'GetProcAddress()'\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG len = 0x10000;
|
||||||
|
NTSTATUS status;
|
||||||
|
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
|
||||||
|
do {
|
||||||
|
if (len > 0x4000000) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
len *= 2;
|
||||||
|
pHandleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)GlobalAlloc(GMEM_ZEROINIT, len);
|
||||||
|
status = pQuerySystemInformation(SystemExtendedHandleInformation, pHandleInfo, len, &len);
|
||||||
|
} while (status == STATUS_INFO_LENGTH_MISMATCH);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(status)) {
|
||||||
|
printf("Failed to call 'NtQuerySystemInformation()' with error code 0x%X\n", status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE currentProcess = GetCurrentProcess();
|
||||||
|
for (int i = 0; i < pHandleInfo->HandleCount; i++) {
|
||||||
|
SYSTEM_HANDLE handle = pHandleInfo->Handles[i];
|
||||||
|
PVOID object = handle.Object;
|
||||||
|
HANDLE handleValue = handle.HandleValue;
|
||||||
|
HANDLE uniqueProcessId = handle.UniqueProcessId;
|
||||||
|
if (NULL != pid && HandleToLong(uniqueProcessId) != pid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
LPSTR pName = NULL;
|
||||||
|
LPSTR pType = NULL;
|
||||||
|
HANDLE sourceProcess = OpenProcess(PROCESS_ALL_ACCESS | PROCESS_DUP_HANDLE | PROCESS_SUSPEND_RESUME, FALSE, HandleToULong(uniqueProcessId));
|
||||||
|
HANDLE targetHandle = NULL;
|
||||||
|
NTSTATUS status = pDuplicateObject(sourceProcess, handleValue, currentProcess, &targetHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||||
|
if (NT_SUCCESS(status)) {
|
||||||
|
//printf("Failed to call 'NtDuplicateObject()' with error code 0x%X\n", status);
|
||||||
|
POBJECT_NAME_INFORMATION pNameInfo = (POBJECT_NAME_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len);
|
||||||
|
POBJECT_TYPE_INFORMATION pTypeInfo = (POBJECT_TYPE_INFORMATION)GlobalAlloc(GMEM_ZEROINIT, len);
|
||||||
|
if (NT_SUCCESS(pQueryObject(targetHandle, ObjectNameInformation, pNameInfo, len, NULL))) {
|
||||||
|
pName = (LPSTR)GlobalAlloc(GMEM_ZEROINIT, pNameInfo->Name.Length);
|
||||||
|
WideCharToMultiByte(CP_ACP, 0, pNameInfo->Name.Buffer, -1, pName, pNameInfo->Name.Length, NULL, NULL);
|
||||||
|
}
|
||||||
|
if (NT_SUCCESS(pQueryObject(targetHandle, ObjectTypeInformation, pTypeInfo, len, NULL))) {
|
||||||
|
pType = (LPSTR)GlobalAlloc(GMEM_ZEROINIT, pTypeInfo->TypeName.Length);
|
||||||
|
WideCharToMultiByte(CP_ACP, 0, pTypeInfo->TypeName.Buffer, -1, pType, pTypeInfo->TypeName.Length, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (NULL != handleName) {
|
||||||
|
|
||||||
|
if (NULL == pName || 0 != strcmp(pName, handleName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return handleValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::wstring Utf8ToUnicode(const char* buffer) {
|
||||||
|
int c_size = MultiByteToWideChar(CP_UTF8, 0, buffer, -1, NULL, 0);
|
||||||
|
if (c_size > 0) {
|
||||||
|
wchar_t* temp = new wchar_t[c_size + 1];
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, buffer, -1, temp, c_size);
|
||||||
|
temp[c_size] = L'\0';
|
||||||
|
std::wstring ret(temp);
|
||||||
|
delete[] temp;
|
||||||
|
temp = NULL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return std::wstring();
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD GetPIDForProcess(wchar_t* process)
|
||||||
|
{
|
||||||
|
HANDLE hSnapshot;
|
||||||
|
DWORD dPid = 0;
|
||||||
|
PROCESSENTRY32W pe32;
|
||||||
|
int working;
|
||||||
|
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||||
|
if (!hSnapshot) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pe32.dwSize = sizeof(PROCESSENTRY32);
|
||||||
|
for (working = Process32FirstW(hSnapshot, &pe32); working; working = Process32NextW(hSnapshot, &pe32))
|
||||||
|
{
|
||||||
|
if (!wcscmp(pe32.szExeFile, process))
|
||||||
|
{
|
||||||
|
dPid = pe32.th32ProcessID;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CloseHandle(hSnapshot);
|
||||||
|
return dPid;
|
||||||
|
}
|
||||||
|
|
||||||
|
HMODULE GetDLLHandle(wchar_t* wDllName, DWORD dPid)
|
||||||
|
{
|
||||||
|
HMODULE result;
|
||||||
|
tagMODULEENTRY32W me32;
|
||||||
|
void* snapMod;
|
||||||
|
|
||||||
|
if (!dPid) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
snapMod = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dPid);
|
||||||
|
me32.dwSize = sizeof(tagMODULEENTRY32W);
|
||||||
|
if (Module32FirstW(snapMod, &me32))
|
||||||
|
{
|
||||||
|
while (wcscmp(wDllName, me32.szModule))
|
||||||
|
{
|
||||||
|
if (!Module32NextW(snapMod, &me32))
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
CloseHandle(snapMod);
|
||||||
|
result = me32.hModule;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error:
|
||||||
|
CloseHandle(snapMod);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL EnableDebugPrivilege()
|
||||||
|
{
|
||||||
|
HANDLE TokenHandle = NULL;
|
||||||
|
TOKEN_PRIVILEGES TokenPrivilege;
|
||||||
|
|
||||||
|
LUID uID;
|
||||||
|
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle)) {
|
||||||
|
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &uID)) {
|
||||||
|
TokenPrivilege.PrivilegeCount = 1;
|
||||||
|
TokenPrivilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
||||||
|
TokenPrivilege.Privileges[0].Luid = uID;
|
||||||
|
if (AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivilege, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
|
||||||
|
CloseHandle(TokenHandle);
|
||||||
|
TokenHandle = INVALID_HANDLE_VALUE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
CloseHandle(TokenHandle);
|
||||||
|
TokenHandle = INVALID_HANDLE_VALUE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned char GetProcAddressAsmCode[] = {
|
||||||
|
0x55, // push ebp;
|
||||||
|
0x8B, 0xEC, // mov ebp, esp;
|
||||||
|
0x83, 0xEC, 0x40, // sub esp, 0x40;
|
||||||
|
0x57, // push edi;
|
||||||
|
0x51, // push ecx;
|
||||||
|
0x8B, 0x7D, 0x08, // mov edi, dword ptr[ebp + 0x8];
|
||||||
|
0x8B, 0x07, // mov eax,dword ptr[edi];
|
||||||
|
0x50, // push eax;
|
||||||
|
0xE8, 0x00, 0x00, 0x00, 0x00, // call GetModuleHandleW;
|
||||||
|
0x83, 0xC4, 0x04, // add esp,0x4;
|
||||||
|
0x83, 0xC7, 0x04, // add edi,0x4;
|
||||||
|
0x8B, 0x0F, // mov ecx, dword ptr[edi];
|
||||||
|
0x51, // push ecx;
|
||||||
|
0x50, // push eax;
|
||||||
|
0xE8, 0x00, 0x00, 0x00, 0x00, // call GetProcAddress;
|
||||||
|
0x83, 0xC4, 0x08, // add esp, 0x8;
|
||||||
|
0x59, // pop ecx;
|
||||||
|
0x5F, // pop edi;
|
||||||
|
0x8B, 0xE5, // mov esp, ebp;
|
||||||
|
0x5D, // pop ebp;
|
||||||
|
0xC3 // retn;
|
||||||
|
};
|
||||||
|
|
||||||
|
LPVOID FillAsmCode(HANDLE handle) {
|
||||||
|
DWORD pGetModuleHandleW = (DWORD)GetModuleHandleW;
|
||||||
|
DWORD pGetProcAddress = (DWORD)GetProcAddress;
|
||||||
|
PVOID fillCall1 = (PVOID)&GetProcAddressAsmCode[15];
|
||||||
|
PVOID fillCall2 = (PVOID)&GetProcAddressAsmCode[30];
|
||||||
|
LPVOID pAsmFuncAddr = VirtualAllocEx(handle, NULL, 1, MEM_COMMIT, PAGE_EXECUTE);
|
||||||
|
if (!pAsmFuncAddr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*(DWORD*)fillCall1 = pGetModuleHandleW - (DWORD)pAsmFuncAddr - 14 - 5;
|
||||||
|
*(DWORD*)fillCall2 = pGetProcAddress - (DWORD)pAsmFuncAddr - 29 - 5;
|
||||||
|
//*(DWORD*)fillCall1 = pGetModuleHandleW ;
|
||||||
|
//*(DWORD*)fillCall2 = pGetProcAddress;
|
||||||
|
SIZE_T dwWriteSize;
|
||||||
|
WriteProcessMemory(handle, pAsmFuncAddr, GetProcAddressAsmCode, sizeof(GetProcAddressAsmCode), &dwWriteSize);
|
||||||
|
return pAsmFuncAddr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int InjectDllAndStartHttp(wchar_t* szPName, wchar_t* szDllPath, DWORD port)
|
||||||
|
{
|
||||||
|
if(!EnableDebugPrivilege()){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int result = 0;
|
||||||
|
HANDLE hRemoteThread = NULL;
|
||||||
|
LPTHREAD_START_ROUTINE lpSysLibAddr = NULL;
|
||||||
|
HINSTANCE__* hKernelModule = NULL;
|
||||||
|
LPVOID lpRemoteDllBase = NULL;
|
||||||
|
HANDLE hProcess;
|
||||||
|
unsigned int dwPid;
|
||||||
|
size_t ulDllLength;
|
||||||
|
wchar_t* dllName = (wchar_t*)L"wxhelper.dll";
|
||||||
|
size_t dllNameLen = wcslen(dllName) * 2 + 2;
|
||||||
|
char* funcName = (char* )"http_start";
|
||||||
|
size_t funcNameLen = strlen(funcName) + 1;
|
||||||
|
|
||||||
|
HANDLE hStartHttp = NULL;
|
||||||
|
LPVOID portAddr = NULL;
|
||||||
|
HANDLE getProcThread = NULL;
|
||||||
|
|
||||||
|
LPVOID paramsAddr = NULL;
|
||||||
|
LPVOID param1Addr = NULL;
|
||||||
|
LPVOID param2Addr = NULL;
|
||||||
|
LPVOID GetProcFuncAddr = NULL;
|
||||||
|
|
||||||
|
DWORD params[2] = { 0 };
|
||||||
|
|
||||||
|
dwPid = GetPIDForProcess(szPName);
|
||||||
|
ulDllLength = (wcslen(szDllPath) + 1) * sizeof(wchar_t);
|
||||||
|
hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwPid);
|
||||||
|
if (!hProcess) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpRemoteDllBase = VirtualAllocEx(hProcess, NULL, ulDllLength, MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
if (lpRemoteDllBase)
|
||||||
|
{
|
||||||
|
if (WriteProcessMemory(hProcess, lpRemoteDllBase, szDllPath, ulDllLength, NULL)
|
||||||
|
&& (hKernelModule = GetModuleHandleW(L"kernel32.dll")) != 0
|
||||||
|
&& (lpSysLibAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(hKernelModule, "LoadLibraryW")) != 0
|
||||||
|
&& (hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, lpSysLibAddr, lpRemoteDllBase, 0, NULL)) != 0)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(hRemoteThread, INFINITE);
|
||||||
|
GetProcFuncAddr = FillAsmCode(hProcess);
|
||||||
|
param1Addr = VirtualAllocEx(hProcess, NULL, dllNameLen, MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
if (param1Addr) {
|
||||||
|
SIZE_T dwWriteSize;
|
||||||
|
BOOL bRet = WriteProcessMemory(hProcess, (LPVOID)param1Addr, dllName, dllNameLen, &dwWriteSize);
|
||||||
|
if (!bRet) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
param2Addr = VirtualAllocEx(hProcess, NULL, funcNameLen, MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
if (param2Addr) {
|
||||||
|
SIZE_T dwWriteSize;
|
||||||
|
BOOL bRet = WriteProcessMemory(hProcess, (LPVOID)param2Addr, funcName, funcNameLen, &dwWriteSize);
|
||||||
|
if (!bRet) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
params[0] = (DWORD)param1Addr;
|
||||||
|
params[1] = (DWORD)param2Addr;
|
||||||
|
|
||||||
|
paramsAddr = VirtualAllocEx(hProcess, NULL, sizeof(params), MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
if (paramsAddr) {
|
||||||
|
SIZE_T dwWriteSize;
|
||||||
|
BOOL bRet = WriteProcessMemory(hProcess, (LPVOID)paramsAddr, ¶ms[0], sizeof(params), &dwWriteSize);
|
||||||
|
if (!bRet) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD dwRet = 0;
|
||||||
|
getProcThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcFuncAddr, paramsAddr, 0, NULL);
|
||||||
|
|
||||||
|
if (getProcThread)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(getProcThread, INFINITE);
|
||||||
|
GetExitCodeThread(getProcThread, &dwRet);
|
||||||
|
if (dwRet) {
|
||||||
|
hStartHttp = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)dwRet, (LPVOID)port, 0, NULL);
|
||||||
|
WaitForSingleObject(hStartHttp, INFINITE);
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error:
|
||||||
|
if (hRemoteThread) {
|
||||||
|
CloseHandle(hRemoteThread);
|
||||||
|
}
|
||||||
|
if (getProcThread) {
|
||||||
|
CloseHandle(getProcThread);
|
||||||
|
}
|
||||||
|
if (hStartHttp) {
|
||||||
|
CloseHandle(hStartHttp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lpRemoteDllBase) {
|
||||||
|
VirtualFreeEx(hProcess, lpRemoteDllBase, ulDllLength, MEM_DECOMMIT | MEM_RELEASE);
|
||||||
|
}
|
||||||
|
if (param1Addr) {
|
||||||
|
VirtualFreeEx(hProcess, param1Addr, dllNameLen, MEM_DECOMMIT | MEM_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param2Addr) {
|
||||||
|
VirtualFreeEx(hProcess, param1Addr, funcNameLen, MEM_DECOMMIT | MEM_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paramsAddr) {
|
||||||
|
VirtualFreeEx(hProcess, param1Addr, sizeof(params), MEM_DECOMMIT | MEM_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetProcFuncAddr) {
|
||||||
|
VirtualFreeEx(hProcess, GetProcFuncAddr, sizeof(GetProcAddressAsmCode), MEM_DECOMMIT | MEM_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int InjectDll(wchar_t* szPName, wchar_t* szDllPath)
|
||||||
|
{
|
||||||
|
if(!EnableDebugPrivilege()){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int result = 0;
|
||||||
|
HANDLE hRemoteThread;
|
||||||
|
LPTHREAD_START_ROUTINE lpSysLibAddr;
|
||||||
|
HINSTANCE__* hKernelModule;
|
||||||
|
LPVOID lpRemoteDllBase;
|
||||||
|
HANDLE hProcess;
|
||||||
|
unsigned int dwPid;
|
||||||
|
size_t ulDllLength;
|
||||||
|
|
||||||
|
dwPid = GetPIDForProcess(szPName);
|
||||||
|
ulDllLength = (wcslen(szDllPath) + 1) * sizeof(wchar_t);
|
||||||
|
hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwPid);
|
||||||
|
if (!hProcess) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpRemoteDllBase = VirtualAllocEx(hProcess, NULL, ulDllLength, MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
if (lpRemoteDllBase)
|
||||||
|
{
|
||||||
|
if (WriteProcessMemory(hProcess, lpRemoteDllBase, szDllPath, ulDllLength, NULL)
|
||||||
|
&& (hKernelModule = GetModuleHandleW(L"kernel32.dll")) != 0
|
||||||
|
&& (lpSysLibAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(hKernelModule, "LoadLibraryW")) != 0
|
||||||
|
&& (hRemoteThread = CreateRemoteThread(hProcess, NULL, 0, lpSysLibAddr, lpRemoteDllBase, 0, NULL)) != 0)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(hRemoteThread, INFINITE);
|
||||||
|
VirtualFreeEx(hProcess, lpRemoteDllBase, ulDllLength, MEM_DECOMMIT | MEM_RELEASE);
|
||||||
|
CloseHandle(hRemoteThread);
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
OutputDebugStringA("[DBG] dll inject success");
|
||||||
|
printf("dll inject success");
|
||||||
|
printf("dll path : %s ", szDllPath);
|
||||||
|
printf("dll path : %d ", dwPid);
|
||||||
|
result = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VirtualFreeEx(hProcess, lpRemoteDllBase, ulDllLength, MEM_DECOMMIT | MEM_RELEASE);
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnInjectDll(wchar_t* szPName, wchar_t* szDName)
|
||||||
|
{
|
||||||
|
HMODULE hDll;
|
||||||
|
HANDLE lpFreeLibAddr;
|
||||||
|
HINSTANCE__* hK32;
|
||||||
|
HANDLE hProcess;
|
||||||
|
unsigned int dwPID;
|
||||||
|
|
||||||
|
dwPID = GetPIDForProcess(szPName);
|
||||||
|
hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwPID);
|
||||||
|
if (!hProcess) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hK32 = GetModuleHandleW(L"Kernel32.dll");
|
||||||
|
if (!hK32) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpFreeLibAddr = GetProcAddress(hK32, "FreeLibraryAndExitThread");
|
||||||
|
//lpFreeLibAddr = (LPTHREAD_START_ROUTINE)GetProcAddress(hK32, "FreeLibrary");
|
||||||
|
hDll = GetDLLHandle(szDName, dwPID);
|
||||||
|
if (hDll) {
|
||||||
|
HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)lpFreeLibAddr, hDll, NULL, NULL);
|
||||||
|
if (hThread == NULL) {
|
||||||
|
int errorCode = GetLastError();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
WaitForSingleObject(hThread, INFINITE);
|
||||||
|
CloseHandle(hThread);
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
FARPROC ShellCode(DWORD param[]) {
|
||||||
|
return GetProcAddress(GetModuleHandleW((LPCWSTR)param[0]), (LPCSTR)param[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
int param;
|
||||||
|
char cInjectprogram[MAX_PATH] = { 0 };
|
||||||
|
char cUnInjectprogram[MAX_PATH] = { 0 };
|
||||||
|
char cDllPath[MAX_PATH] = { 0 };
|
||||||
|
char cDllName[MAX_PATH] = { 0 };
|
||||||
|
int port = 0;
|
||||||
|
|
||||||
|
ULONG pid = 0;
|
||||||
|
|
||||||
|
while ((param = getopt(argc, argv, "i:p:u:d:m:P:h")) != -1)
|
||||||
|
{
|
||||||
|
switch (param)
|
||||||
|
{
|
||||||
|
case 'i':
|
||||||
|
strcpy(cInjectprogram, optarg);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
strcpy(cDllPath, optarg);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
strcpy(cUnInjectprogram, optarg);
|
||||||
|
case 'd':
|
||||||
|
strcpy(cDllName, optarg);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
printf("Usage: %s [-i/u] [-p/d] [-m]\n", argv[0]);
|
||||||
|
printf("Options:\n");
|
||||||
|
printf(" -h Print this help message.\n");
|
||||||
|
printf(" -i <program name> Name of the running program to be injected.\n");
|
||||||
|
printf(" -u <program name> Name of the running program to be uninstalled.\n");
|
||||||
|
printf(" -p <path> Full path of injection file.\n");
|
||||||
|
printf(" -d <file> Name of injection file.\n");
|
||||||
|
printf(" -m <pid> WeChat.exe pid.\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("Examples:\n");
|
||||||
|
printf(" window> %s -i test.exe -p c:/inject.dll \n", argv[0]);
|
||||||
|
printf(" window> %s -u test.exe -d inject.dll \n", argv[0]);
|
||||||
|
printf(" window> %s -m 1988 \n", argv[0]);
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
pid = std::stol(optarg);
|
||||||
|
break;
|
||||||
|
case 'P':
|
||||||
|
port = std::atoi(optarg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid) {
|
||||||
|
FindHandles(pid, (LPSTR)"_WeChat_App_Instance_Identity_Mutex_Name", TRUE, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cInjectprogram[0] != 0 && cDllPath[0] != 0)
|
||||||
|
{
|
||||||
|
if (cInjectprogram[0] != '\0' && cDllPath[0] != '\0')
|
||||||
|
{
|
||||||
|
if (port == 0) {
|
||||||
|
std::wstring wsProgram = Utf8ToUnicode(cInjectprogram);
|
||||||
|
std::wstring wsPath = Utf8ToUnicode(cDllPath);
|
||||||
|
int ret = InjectDll((wchar_t*)wsProgram.c_str(), (wchar_t*)wsPath.c_str());
|
||||||
|
printf(" 注入结果:%i \n", ret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::wstring wsProgram = Utf8ToUnicode(cInjectprogram);
|
||||||
|
std::wstring wsPath = Utf8ToUnicode(cDllPath);
|
||||||
|
int ret = InjectDllAndStartHttp((wchar_t*)wsProgram.c_str(), (wchar_t*)wsPath.c_str(), port);
|
||||||
|
printf(" 注入结果:%i \n", ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cUnInjectprogram[0] != 0 && cDllName[0] != 0)
|
||||||
|
{
|
||||||
|
if (cUnInjectprogram[0] != '\0' && cDllName[0] != '\0')
|
||||||
|
{
|
||||||
|
std::wstring wsUnInjectProgram = Utf8ToUnicode(cUnInjectprogram);
|
||||||
|
std::wstring wsName = Utf8ToUnicode(cDllName);
|
||||||
|
int ret = UnInjectDll((wchar_t*)wsUnInjectProgram.c_str(), (wchar_t*)wsName.c_str());
|
||||||
|
printf(" 卸载结果:%i \n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
219
src/account_mgr.cc
Normal file
219
src/account_mgr.cc
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "account_mgr.h"
|
||||||
|
#include "easylogging++.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "wechat_function.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
namespace wxhelper {
|
||||||
|
AccountMgr::AccountMgr(DWORD base):BaseMgr(base){
|
||||||
|
|
||||||
|
}
|
||||||
|
AccountMgr::~AccountMgr(){
|
||||||
|
|
||||||
|
}
|
||||||
|
int AccountMgr::GetSelfInfo(SelfInfoInner &out) {
|
||||||
|
DWORD accout_service_addr = base_addr_ + WX_ACCOUNT_SERVICE_OFFSET;
|
||||||
|
DWORD get_app_save_addr = base_addr_ + WX_GET_APP_DATA_SAVE_PATH_OFFSET;
|
||||||
|
DWORD get_current_data_path_addr = base_addr_ + WX_GET_CURRENT_DATA_PATH_OFFSET;
|
||||||
|
DWORD service_addr = NULL;
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
CALL accout_service_addr
|
||||||
|
MOV service_addr,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
if (service_addr) {
|
||||||
|
if (*(DWORD *)(service_addr + 0x44) == 0 ||
|
||||||
|
*(DWORD *)(service_addr + 0x44 + 0x10) == 0) {
|
||||||
|
out.wxid = string();
|
||||||
|
} else {
|
||||||
|
if (*(DWORD *)(service_addr + 0x44 + 0x14) == 0xF) {
|
||||||
|
out.wxid = string((char *)(service_addr + 0x44),
|
||||||
|
*(DWORD *)(service_addr + 0x44 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.wxid = string(*(char **)(service_addr + 0x44),
|
||||||
|
*(DWORD *)(service_addr + 0x44 + 0x10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(DWORD *)(service_addr + 0xA8) == 0 ||
|
||||||
|
*(DWORD *)(service_addr + 0xA8 + 0x10) == 0) {
|
||||||
|
out.account = string();
|
||||||
|
} else {
|
||||||
|
if (*(DWORD *)(service_addr + 0xA8 + 0x14) == 0xF) {
|
||||||
|
out.account = string((char *)(service_addr + 0xA8),
|
||||||
|
*(DWORD *)(service_addr + 0xA8 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.account = string(*(char **)(service_addr + 0xA8),
|
||||||
|
*(DWORD *)(service_addr + 0xA8 + 0x10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(DWORD *)(service_addr + 0xC0) == 0 ||
|
||||||
|
*(DWORD *)(service_addr + 0xC0 + 0x10) == 0) {
|
||||||
|
out.mobile = string();
|
||||||
|
} else {
|
||||||
|
if (*(DWORD *)(service_addr + 0xC0 + 0x14) == 0xF) {
|
||||||
|
out.mobile = string((char *)(service_addr + 0xC0),
|
||||||
|
*(DWORD *)(service_addr + 0xC0 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.mobile = string(*(char **)(service_addr + 0xC0),
|
||||||
|
*(DWORD *)(service_addr + 0xC0 + 0x10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(DWORD *)(service_addr + 0xD8) == 0 ||
|
||||||
|
*(DWORD *)(service_addr + 0xD8 + 0x10) == 0) {
|
||||||
|
out.signature = string();
|
||||||
|
} else {
|
||||||
|
if (*(DWORD *)(service_addr + 0xD8 + 0x14) == 0xF) {
|
||||||
|
out.signature = string((char *)(service_addr + 0xD8),
|
||||||
|
*(DWORD *)(service_addr + 0xD8 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.signature = string(*(char **)(service_addr + 0xD8),
|
||||||
|
*(DWORD *)(service_addr + 0xD8 + 0x10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(DWORD *)(service_addr + 0xF0) == 0 ||
|
||||||
|
*(DWORD *)(service_addr + 0xF0 + 0x10) == 0) {
|
||||||
|
out.country = string();
|
||||||
|
} else {
|
||||||
|
if (*(DWORD *)(service_addr + 0xF0 + 0x14) == 0xF) {
|
||||||
|
out.country = string((char *)(service_addr + 0xF0),
|
||||||
|
*(DWORD *)(service_addr + 0xF0 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.country = string(*(char **)(service_addr + 0xF0),
|
||||||
|
*(DWORD *)(service_addr + 0xF0 + 0x10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(DWORD *)(service_addr + 0x108) == 0 ||
|
||||||
|
*(DWORD *)(service_addr + 0x108 + 0x10) == 0) {
|
||||||
|
out.province = string();
|
||||||
|
} else {
|
||||||
|
if (*(DWORD *)(service_addr + 0x108 + 0x14) == 0xF) {
|
||||||
|
out.province = string((char *)(service_addr + 0x108),
|
||||||
|
*(DWORD *)(service_addr + 0x108 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.province = string(*(char **)(service_addr + 0x108),
|
||||||
|
*(DWORD *)(service_addr + 0x108 + 0x10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(DWORD *)(service_addr + 0x120) == 0 ||
|
||||||
|
*(DWORD *)(service_addr + 0x120 + 0x10) == 0) {
|
||||||
|
out.city = string();
|
||||||
|
} else {
|
||||||
|
if (*(DWORD *)(service_addr + 0x120 + 0x14) == 0xF) {
|
||||||
|
out.city = string((char *)(service_addr + 0x120),
|
||||||
|
*(DWORD *)(service_addr + 0x120 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.city = string(*(char **)(service_addr + 0x120),
|
||||||
|
*(DWORD *)(service_addr + 0x120 + 0x10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(DWORD *)(service_addr + 0x150) == 0 ||
|
||||||
|
*(DWORD *)(service_addr + 0x150 + 0x10) == 0) {
|
||||||
|
out.name = string();
|
||||||
|
} else {
|
||||||
|
if (*(DWORD *)(service_addr + 0x150 + 0x14) == 0xF) {
|
||||||
|
out.name = string((char *)(service_addr + 0x150),
|
||||||
|
*(DWORD *)(service_addr + 0x150 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.name = string(*(char **)(service_addr + 0x150),
|
||||||
|
*(DWORD *)(service_addr + 0x150 + 0x10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(DWORD *)(service_addr + 0x304) == 0 ||
|
||||||
|
*(DWORD *)(service_addr + 0x304 + 0x10) == 0) {
|
||||||
|
out.head_img = string();
|
||||||
|
} else {
|
||||||
|
if (*(DWORD *)(service_addr + 0x304 + 0x14) == 0xF) {
|
||||||
|
out.head_img = string((char *)(service_addr + 0x304),
|
||||||
|
*(DWORD *)(service_addr + 0x304 + 0x10));
|
||||||
|
} else {
|
||||||
|
out.head_img = string(*(char **)(service_addr + 0x304),
|
||||||
|
*(DWORD *)(service_addr + 0x304 + 0x10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(DWORD *)(service_addr + 0x4CC) == 0 ||
|
||||||
|
*(DWORD *)(service_addr + 0x4D0) == 0) {
|
||||||
|
out.db_key = string();
|
||||||
|
} else {
|
||||||
|
DWORD byte_addr = *(DWORD *)(service_addr + 0x4CC);
|
||||||
|
DWORD len = *(DWORD *)(service_addr + 0x4D0);
|
||||||
|
out.db_key = Utils::Bytes2Hex((BYTE *)byte_addr, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WeChatString data_save_path;
|
||||||
|
WeChatString current_data_path;
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
LEA ECX,data_save_path
|
||||||
|
CALL get_app_save_addr
|
||||||
|
LEA ECX,current_data_path
|
||||||
|
CALL get_current_data_path_addr
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data_save_path.ptr) {
|
||||||
|
out.data_save_path = Utils::WstringToUTF8(
|
||||||
|
wstring(data_save_path.ptr, data_save_path.length));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out.data_save_path = string();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_data_path.ptr) {
|
||||||
|
out.current_data_path = Utils::WstringToUTF8(
|
||||||
|
wstring(current_data_path.ptr, current_data_path.length));
|
||||||
|
} else {
|
||||||
|
out.current_data_path = string();
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AccountMgr::CheckLogin() {
|
||||||
|
int success = -1;
|
||||||
|
DWORD accout_service_addr = base_addr_ + WX_ACCOUNT_SERVICE_OFFSET;
|
||||||
|
DWORD service_addr = NULL;
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
CALL accout_service_addr
|
||||||
|
MOV service_addr,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
if (service_addr) {
|
||||||
|
success = *(DWORD *)(service_addr + 0x4C8);
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AccountMgr::Logout() {
|
||||||
|
int success = -1;
|
||||||
|
if (!CheckLogin()) {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
DWORD account_service_addr = base_addr_ + WX_ACCOUNT_SERVICE_OFFSET;
|
||||||
|
DWORD logout_addr = base_addr_ + WX_LOGOUT_OFFSET;
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
CALL account_service_addr
|
||||||
|
PUSH 0x0
|
||||||
|
MOV ECX,EAX
|
||||||
|
CALL logout_addr
|
||||||
|
MOV success,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wxhelper
|
19
src/account_mgr.h
Normal file
19
src/account_mgr.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef WXHELPER_ACCOUNT_MGR_H_
|
||||||
|
#define WXHELPER_ACCOUNT_MGR_H_
|
||||||
|
#include "wechat_function.h"
|
||||||
|
#include"base_mgr.h"
|
||||||
|
namespace wxhelper{
|
||||||
|
class AccountMgr: public BaseMgr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AccountMgr(DWORD base);
|
||||||
|
~AccountMgr();
|
||||||
|
int GetSelfInfo(SelfInfoInner& out);
|
||||||
|
|
||||||
|
int CheckLogin();
|
||||||
|
|
||||||
|
int Logout();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
78
src/api_route.h
Normal file
78
src/api_route.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#ifndef WXHELPER_API_ROUTINES_H_
|
||||||
|
#define WXHELPER_API_ROUTINES_H_
|
||||||
|
namespace wxhelper {
|
||||||
|
|
||||||
|
typedef enum HTTP_API_ROUTE {
|
||||||
|
// login check
|
||||||
|
WECHAT_IS_LOGIN = 0,
|
||||||
|
// self info
|
||||||
|
WECHAT_GET_SELF_INFO,
|
||||||
|
// send message
|
||||||
|
WECHAT_MSG_SEND_TEXT,
|
||||||
|
WECHAT_MSG_SEND_AT,
|
||||||
|
WECHAT_MSG_SEND_CARD,
|
||||||
|
WECHAT_MSG_SEND_IMAGE,
|
||||||
|
WECHAT_MSG_SEND_FILE,
|
||||||
|
WECHAT_MSG_SEND_ARTICLE,
|
||||||
|
WECHAT_MSG_SEND_APP,
|
||||||
|
// receive message
|
||||||
|
WECHAT_MSG_START_HOOK,
|
||||||
|
WECHAT_MSG_STOP_HOOK,
|
||||||
|
WECHAT_MSG_START_IMAGE_HOOK,
|
||||||
|
WECHAT_MSG_STOP_IMAGE_HOOK,
|
||||||
|
WECHAT_MSG_START_VOICE_HOOK,
|
||||||
|
WECHAT_MSG_STOP_VOICE_HOOK,
|
||||||
|
// contact
|
||||||
|
WECHAT_CONTACT_GET_LIST,
|
||||||
|
WECHAT_CONTACT_CHECK_STATUS,
|
||||||
|
WECHAT_CONTACT_DEL,
|
||||||
|
WECHAT_CONTACT_SEARCH_BY_CACHE,
|
||||||
|
WECHAT_CONTACT_SEARCH_BY_NET,
|
||||||
|
WECHAT_CONTACT_ADD_BY_WXID,
|
||||||
|
WECHAT_CONTACT_ADD_BY_V3,
|
||||||
|
WECHAT_CONTACT_ADD_BY_PUBLIC_ID,
|
||||||
|
WECHAT_CONTACT_VERIFY_APPLY,
|
||||||
|
WECHAT_CONTACT_EDIT_REMARK,
|
||||||
|
// chatroom
|
||||||
|
WECHAT_CHATROOM_GET_MEMBER_LIST,
|
||||||
|
WECHAT_CHATROOM_GET_MEMBER_NICKNAME,
|
||||||
|
WECHAT_CHATROOM_DEL_MEMBER,
|
||||||
|
WECHAT_CHATROOM_ADD_MEMBER,
|
||||||
|
WECHAT_CHATROOM_SET_ANNOUNCEMENT,
|
||||||
|
WECHAT_CHATROOM_SET_CHATROOM_NAME,
|
||||||
|
WECHAT_CHATROOM_SET_SELF_NICKNAME,
|
||||||
|
// database
|
||||||
|
WECHAT_DATABASE_GET_HANDLES,
|
||||||
|
WECHAT_DATABASE_BACKUP,
|
||||||
|
WECHAT_DATABASE_QUERY,
|
||||||
|
// version
|
||||||
|
WECHAT_SET_VERSION,
|
||||||
|
// log
|
||||||
|
WECHAT_LOG_START_HOOK,
|
||||||
|
WECHAT_LOG_STOP_HOOK,
|
||||||
|
// browser
|
||||||
|
WECHAT_BROWSER_OPEN_WITH_URL,
|
||||||
|
WECHAT_GET_PUBLIC_MSG,
|
||||||
|
WECHAT_MSG_FORWARD_MESSAGE,
|
||||||
|
WECHAT_GET_QRCODE_IMAGE,
|
||||||
|
WECHAT_GET_A8KEY,
|
||||||
|
WECHAT_MSG_SEND_XML,
|
||||||
|
WECHAT_LOGOUT,
|
||||||
|
WECHAT_GET_TRANSFER,
|
||||||
|
WECHAT_GET_CONTACT_ALL,
|
||||||
|
WECHAT_GET_CHATROOM_INFO,
|
||||||
|
WECHAT_GET_IMG_BY_NAME,
|
||||||
|
WECHAT_DO_OCR,
|
||||||
|
WECHAT_SEND_PAT_MSG,
|
||||||
|
WECHAT_SET_TOP_MSG,
|
||||||
|
WECHAT_REMOVE_TOP_MSG,
|
||||||
|
WECHAT_SNS_GET_FIRST_PAGE,
|
||||||
|
WECHAT_SNS_GET_NEXT_PAGE,
|
||||||
|
WECHAT_CONTACT_NAME,
|
||||||
|
WECHAT_ATTACH_DOWNLOAD,
|
||||||
|
WECHAT_GET_VOICE,
|
||||||
|
} WECHAT_HTTP_APIS,
|
||||||
|
*PWECHAT_HTTP_APIS;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
13
src/base_mgr.cc
Normal file
13
src/base_mgr.cc
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include "base_mgr.h"
|
||||||
|
|
||||||
|
namespace wxhelper{
|
||||||
|
|
||||||
|
BaseMgr::BaseMgr(DWORD base):base_addr_(base)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseMgr::~BaseMgr()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
13
src/base_mgr.h
Normal file
13
src/base_mgr.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef WXHELPER_BASE_MGR_H_
|
||||||
|
#define WXHELPER_BASE_MGR_H_
|
||||||
|
#include <Windows.h>
|
||||||
|
namespace wxhelper{
|
||||||
|
class BaseMgr{
|
||||||
|
public:
|
||||||
|
explicit BaseMgr(DWORD base);
|
||||||
|
~BaseMgr();
|
||||||
|
protected:
|
||||||
|
DWORD base_addr_;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
375
src/chat_room_mgr.cc
Normal file
375
src/chat_room_mgr.cc
Normal file
@ -0,0 +1,375 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "chat_room_mgr.h"
|
||||||
|
|
||||||
|
#include "db.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace wxhelper {
|
||||||
|
|
||||||
|
ChatRoomMgr::ChatRoomMgr(DWORD base) : BaseMgr(base) {}
|
||||||
|
|
||||||
|
ChatRoomMgr::~ChatRoomMgr() {}
|
||||||
|
|
||||||
|
int ChatRoomMgr::GetChatRoomDetailInfo(wchar_t* chat_room_id,
|
||||||
|
ChatRoomInfoInner& room_info) {
|
||||||
|
int success = -1;
|
||||||
|
WeChatString chat_room(chat_room_id);
|
||||||
|
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||||
|
DWORD get_chat_room_detail_addr =
|
||||||
|
base_addr_ + WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET;
|
||||||
|
DWORD create_chat_room_info_addr = base_addr_ + WX_NEW_CHAT_ROOM_INFO_OFFSET;
|
||||||
|
DWORD free_chat_room_info_addr = base_addr_ + WX_FREE_CHAT_ROOM_INFO_OFFSET;
|
||||||
|
char chat_room_info[0xDC] = {0};
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
LEA ECX,chat_room_info
|
||||||
|
CALL create_chat_room_info_addr
|
||||||
|
CALL get_chat_room_mgr_addr
|
||||||
|
PUSH 0x0
|
||||||
|
LEA ECX,chat_room_info
|
||||||
|
PUSH ECX
|
||||||
|
LEA ECX,chat_room
|
||||||
|
PUSH ECX
|
||||||
|
MOV ECX,EAX
|
||||||
|
CALL get_chat_room_detail_addr
|
||||||
|
MOV success,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
DWORD room_id_len = *(DWORD*)(chat_room_info + 0x8);
|
||||||
|
DWORD room_id_max_len = *(DWORD*)(chat_room_info + 0xC);
|
||||||
|
wchar_t* room_id = new wchar_t[room_id_len + 1];
|
||||||
|
wmemcpy(room_id, *(wchar_t**)(chat_room_info + 0x4), room_id_len + 1);
|
||||||
|
room_info.chat_room_id.ptr = room_id;
|
||||||
|
room_info.chat_room_id.length = room_id_len;
|
||||||
|
room_info.chat_room_id.max_length = room_id_max_len;
|
||||||
|
|
||||||
|
DWORD notice_len = *(DWORD*)(chat_room_info + 0x1C);
|
||||||
|
DWORD notice_max_len = *(DWORD*)(chat_room_info + 0x20);
|
||||||
|
wchar_t* notice_ptr = *(wchar_t**)(chat_room_info + 0x18);
|
||||||
|
if (notice_len <= 0) {
|
||||||
|
room_info.notice.ptr = nullptr;
|
||||||
|
} else {
|
||||||
|
wchar_t* notice = new wchar_t[notice_len + 1];
|
||||||
|
wmemcpy(notice, notice_ptr, notice_len + 1);
|
||||||
|
room_info.notice.ptr = notice;
|
||||||
|
}
|
||||||
|
room_info.notice.length = notice_len;
|
||||||
|
room_info.notice.max_length = notice_max_len;
|
||||||
|
|
||||||
|
DWORD admin_len = *(DWORD*)(chat_room_info + 0x30);
|
||||||
|
DWORD admin_max_len = *(DWORD*)(chat_room_info + 0x34);
|
||||||
|
wchar_t* admin_ptr = *(wchar_t**)(chat_room_info + 0x2C);
|
||||||
|
if (admin_len <= 0) {
|
||||||
|
room_info.admin.ptr = nullptr;
|
||||||
|
} else {
|
||||||
|
wchar_t* admin = new wchar_t[admin_len + 1];
|
||||||
|
wmemcpy(admin, admin_ptr, admin_len + 1);
|
||||||
|
room_info.admin.ptr = admin;
|
||||||
|
}
|
||||||
|
room_info.admin.length = admin_len;
|
||||||
|
room_info.admin.max_length = admin_max_len;
|
||||||
|
|
||||||
|
DWORD xml_len = *(DWORD*)(chat_room_info + 0x54);
|
||||||
|
DWORD xml_max_len = *(DWORD*)(chat_room_info + 0x58);
|
||||||
|
wchar_t* xml_ptr = *(wchar_t**)(chat_room_info + 0x50);
|
||||||
|
if (xml_len <= 0) {
|
||||||
|
room_info.xml.ptr = nullptr;
|
||||||
|
} else {
|
||||||
|
wchar_t* xml = new wchar_t[xml_len + 1];
|
||||||
|
wmemcpy(xml, xml_ptr, xml_len + 1);
|
||||||
|
room_info.xml.ptr = xml;
|
||||||
|
}
|
||||||
|
room_info.xml.length = xml_len;
|
||||||
|
room_info.xml.max_length = xml_max_len;
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
LEA ECX,chat_room_info
|
||||||
|
CALL free_chat_room_info_addr
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ChatRoomMgr::DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids,
|
||||||
|
int len) {
|
||||||
|
int success = 0;
|
||||||
|
WeChatString chat_room(chat_room_id);
|
||||||
|
vector<WeChatString> members;
|
||||||
|
VectorInner* list = (VectorInner*)&members;
|
||||||
|
DWORD members_ptr = (DWORD)&list->start;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
WeChatString pwxid(wxids[i]);
|
||||||
|
members.push_back(pwxid);
|
||||||
|
}
|
||||||
|
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||||
|
DWORD del_member_addr = base_addr_ + WX_DEL_CHAT_ROOM_MEMBER_OFFSET;
|
||||||
|
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
CALL get_chat_room_mgr_addr
|
||||||
|
SUB ESP,0x14
|
||||||
|
MOV ESI,EAX
|
||||||
|
MOV ECX,ESP
|
||||||
|
LEA EDI,chat_room
|
||||||
|
PUSH EDI
|
||||||
|
CALL init_chat_msg_addr
|
||||||
|
MOV ECX,ESI
|
||||||
|
MOV EAX,dword ptr[members_ptr]
|
||||||
|
PUSH EAX
|
||||||
|
CALL del_member_addr
|
||||||
|
MOV success,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ChatRoomMgr::AddMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids,
|
||||||
|
int len) {
|
||||||
|
int success = -1;
|
||||||
|
WeChatString chat_room(chat_room_id);
|
||||||
|
vector<WeChatString> members;
|
||||||
|
VectorInner* list = (VectorInner*)&members;
|
||||||
|
DWORD members_ptr = (DWORD)&list->start;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
WeChatString pwxid(wxids[i]);
|
||||||
|
members.push_back(pwxid);
|
||||||
|
}
|
||||||
|
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||||
|
DWORD add_member_addr = base_addr_ + WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET;
|
||||||
|
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||||
|
DWORD temp = 0;
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
CALL get_chat_room_mgr_addr
|
||||||
|
SUB ESP,0x8
|
||||||
|
MOV temp,EAX
|
||||||
|
MOV ECX,ESP
|
||||||
|
MOV dword ptr [ECX],0x0
|
||||||
|
MOV dword ptr [ECX + 4],0x0
|
||||||
|
TEST ESI,ESI
|
||||||
|
SUB ESP,0x14
|
||||||
|
MOV ECX,ESP
|
||||||
|
LEA EAX,chat_room
|
||||||
|
PUSH EAX
|
||||||
|
CALL init_chat_msg_addr
|
||||||
|
MOV ECX,temp
|
||||||
|
MOV EAX,dword ptr[members_ptr]
|
||||||
|
PUSH EAX
|
||||||
|
CALL add_member_addr
|
||||||
|
MOV success,EAX
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ChatRoomMgr::GetMemberFromChatRoom(wchar_t* chat_room_id,
|
||||||
|
ChatRoomInner& out) {
|
||||||
|
int success = -1;
|
||||||
|
WeChatString chat_room(chat_room_id);
|
||||||
|
DWORD chat_room_ptr = (DWORD)&chat_room;
|
||||||
|
char buffer[0x1D4] = {0};
|
||||||
|
DWORD get_member_addr = base_addr_ + WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET;
|
||||||
|
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||||
|
DWORD create_chat_room_addr = base_addr_ + WX_INIT_CHAT_ROOM_OFFSET;
|
||||||
|
DWORD free_chat_room_addr = base_addr_ + WX_FREE_CHAT_ROOM_OFFSET;
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
LEA ECX,buffer
|
||||||
|
CALL create_chat_room_addr
|
||||||
|
CALL get_chat_room_mgr_addr
|
||||||
|
LEA EAX, buffer
|
||||||
|
PUSH EAX
|
||||||
|
PUSH chat_room_ptr
|
||||||
|
CALL get_member_addr
|
||||||
|
MOVZX EAX,AL
|
||||||
|
MOV success,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
char* members = *(char**)(buffer + 0x1c);
|
||||||
|
wchar_t* room = *(wchar_t**)(buffer + 0x8);
|
||||||
|
wchar_t* admin = *(wchar_t**)(buffer + 0x4c);
|
||||||
|
|
||||||
|
out.members = new char[strlen(members) + 1];
|
||||||
|
memcpy(out.members, members, strlen(members) + 1);
|
||||||
|
|
||||||
|
out.chat_room = new wchar_t[wcslen(room) + 1];
|
||||||
|
wmemcpy(out.chat_room, room, wcslen(room) + 1);
|
||||||
|
|
||||||
|
out.admin = new wchar_t[wcslen(admin) + 1];
|
||||||
|
wmemcpy(out.admin, admin, wcslen(admin) + 1);
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
LEA ECX,buffer
|
||||||
|
CALL free_chat_room_addr
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ChatRoomMgr::ModChatRoomMemberNickName(wchar_t* chat_room_id, wchar_t* wxid,
|
||||||
|
wchar_t* nick) {
|
||||||
|
int success = -1;
|
||||||
|
WeChatString chat_room(chat_room_id);
|
||||||
|
WeChatString self_wxid(wxid);
|
||||||
|
WeChatString new_nick(nick);
|
||||||
|
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||||
|
DWORD mod_member_nick_name_addr =
|
||||||
|
base_addr_ + WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET;
|
||||||
|
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
CALL get_chat_room_mgr_addr
|
||||||
|
SUB ESP,0x14
|
||||||
|
MOV ECX,ESP
|
||||||
|
LEA EDI,new_nick
|
||||||
|
PUSH EDI
|
||||||
|
CALL init_chat_msg_addr
|
||||||
|
SUB ESP,0x14
|
||||||
|
LEA EAX,self_wxid
|
||||||
|
MOV ECX,ESP
|
||||||
|
PUSH EAX
|
||||||
|
CALL init_chat_msg_addr
|
||||||
|
SUB ESP,0x14
|
||||||
|
LEA EAX,chat_room
|
||||||
|
MOV ECX,ESP
|
||||||
|
PUSH EAX
|
||||||
|
CALL init_chat_msg_addr
|
||||||
|
CALL mod_member_nick_name_addr
|
||||||
|
MOVZX EAX,AL
|
||||||
|
MOV success,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ChatRoomMgr::SetTopMsg(wchar_t* wxid, ULONG64 msg_id) {
|
||||||
|
int success = -1;
|
||||||
|
char chat_msg[0x2D8] = {0};
|
||||||
|
DWORD new_chat_msg_addr = base_addr_ + WX_NEW_CHAT_MSG_OFFSET;
|
||||||
|
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||||
|
DWORD handle_top_msg_addr = base_addr_ + WX_TOP_MSG_OFFSET;
|
||||||
|
DWORD free_addr = base_addr_ + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET;
|
||||||
|
DWORD get_chat_mgr_addr = base_addr_ + WX_CHAT_MGR_OFFSET;
|
||||||
|
DWORD get_by_local_Id_addr = base_addr_ + WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET;
|
||||||
|
|
||||||
|
|
||||||
|
int db_index = 0;
|
||||||
|
int local_id = DB::GetInstance().GetLocalIdByMsgId(msg_id, db_index);
|
||||||
|
if (local_id < 1) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
__asm{
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
CALL new_chat_msg_addr
|
||||||
|
CALL get_chat_mgr_addr
|
||||||
|
PUSH dword ptr [db_index]
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
PUSH dword ptr [local_id]
|
||||||
|
CALL get_by_local_Id_addr
|
||||||
|
ADD ESP,0x8
|
||||||
|
CALL get_chat_room_mgr_addr
|
||||||
|
PUSH 0x0
|
||||||
|
LEA EAX,chat_msg
|
||||||
|
PUSH EAX
|
||||||
|
CALL handle_top_msg_addr
|
||||||
|
MOV success,EAX
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
PUSH 0x0
|
||||||
|
CALL free_addr
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ChatRoomMgr::RemoveTopMsg(wchar_t* chat_room_id, ULONG64 msg_id) {
|
||||||
|
int success = -1;
|
||||||
|
WeChatString chat_room(chat_room_id);
|
||||||
|
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||||
|
DWORD new_chat_msg_addr = base_addr_ + WX_NEW_CHAT_MSG_OFFSET;
|
||||||
|
DWORD init_chat_msg_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||||
|
DWORD remove_top_msg_addr = base_addr_ + WX_REMOVE_TOP_MSG_OFFSET;
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
CALL get_chat_room_mgr_addr
|
||||||
|
MOV EDI,dword ptr [msg_id]
|
||||||
|
LEA EAX,chat_room
|
||||||
|
MOV ESI,dword ptr [msg_id + 0x4]
|
||||||
|
SUB ESP,0x14
|
||||||
|
MOV ECX,ESP
|
||||||
|
PUSH EAX
|
||||||
|
CALL init_chat_msg_addr
|
||||||
|
PUSH ESI
|
||||||
|
PUSH EDI
|
||||||
|
CALL remove_top_msg_addr
|
||||||
|
MOV success,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring ChatRoomMgr::GetChatRoomMemberNickname(wchar_t* chat_room_id,
|
||||||
|
wchar_t* wxid) {
|
||||||
|
WeChatString chat_room(chat_room_id);
|
||||||
|
WeChatString member_id(wxid);
|
||||||
|
WeChatString nickname(NULL);
|
||||||
|
DWORD get_chat_room_mgr_addr = base_addr_ + WX_CHAT_ROOM_MGR_OFFSET;
|
||||||
|
DWORD get_nickname_addr = base_addr_ + WX_GET_MEMBER_NICKNAME_OFFSET;
|
||||||
|
DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET;
|
||||||
|
DWORD get_contact_addr = base_addr_ + WX_GET_CONTACT_OFFSET;
|
||||||
|
DWORD free_contact_addr = base_addr_ + WX_FREE_CONTACT_OFFSET;
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
CALL get_chat_room_mgr_addr
|
||||||
|
LEA ECX,nickname
|
||||||
|
PUSH ECX
|
||||||
|
LEA ECX,member_id
|
||||||
|
PUSH ECX
|
||||||
|
LEA ECX,chat_room
|
||||||
|
PUSH ECX
|
||||||
|
MOV ECX,EAX
|
||||||
|
CALL get_nickname_addr
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
wstring name = L"";
|
||||||
|
if (nickname.ptr) {
|
||||||
|
name += wstring(nickname.ptr);
|
||||||
|
} else {
|
||||||
|
char buff[0x440] = {0};
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
CALL contact_mgr_addr
|
||||||
|
LEA ECX,buff
|
||||||
|
PUSH ECX
|
||||||
|
LEA ECX,member_id
|
||||||
|
PUSH ECX
|
||||||
|
MOV ECX,EAX
|
||||||
|
CALL get_contact_addr
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
name += READ_WSTRING(buff, 0x6C);
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
LEA ECX,buff
|
||||||
|
CALL free_contact_addr
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
} // namespace wxhelper
|
28
src/chat_room_mgr.h
Normal file
28
src/chat_room_mgr.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef WXHELPER_CHAT_ROOM_MGR_H_
|
||||||
|
#define WXHELPER_CHAT_ROOM_MGR_H_
|
||||||
|
#include "wechat_function.h"
|
||||||
|
#include "base_mgr.h"
|
||||||
|
namespace wxhelper {
|
||||||
|
class ChatRoomMgr:public BaseMgr {
|
||||||
|
public:
|
||||||
|
explicit ChatRoomMgr(DWORD base);
|
||||||
|
~ChatRoomMgr();
|
||||||
|
int GetChatRoomDetailInfo(wchar_t* chat_room_id,
|
||||||
|
ChatRoomInfoInner& room_info);
|
||||||
|
int DelMemberFromChatRoom(wchar_t* chat_room_id, wchar_t** wxids,
|
||||||
|
int len);
|
||||||
|
int AddMemberToChatRoom(wchar_t* chat_room_id, wchar_t** wxids,
|
||||||
|
int len);
|
||||||
|
|
||||||
|
int GetMemberFromChatRoom(wchar_t* chat_room_id, ChatRoomInner& out);
|
||||||
|
int ModChatRoomMemberNickName(wchar_t* chat_room_id, wchar_t* wxid,
|
||||||
|
wchar_t* nick);
|
||||||
|
|
||||||
|
int SetTopMsg(wchar_t* wxid, ULONG64 msg_id);
|
||||||
|
int RemoveTopMsg(wchar_t* chat_room_id, ULONG64 msg_id);
|
||||||
|
|
||||||
|
std::wstring GetChatRoomMemberNickname(wchar_t* chat_room_id,
|
||||||
|
wchar_t* wxid);
|
||||||
|
};
|
||||||
|
} // namespace wxhelper
|
||||||
|
#endif
|
6
src/config.cc
Normal file
6
src/config.cc
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#include "config.h"
|
||||||
|
namespace wxhelper {
|
||||||
|
Config::Config(/* args */) {}
|
||||||
|
|
||||||
|
Config::~Config() {}
|
||||||
|
} // namespace wxhelper
|
15
src/config.h
Normal file
15
src/config.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef WXHELPER_CONFIG_H_
|
||||||
|
#define WXHELPER_CONFIG_H_
|
||||||
|
|
||||||
|
namespace wxhelper{
|
||||||
|
|
||||||
|
class Config
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/* data */
|
||||||
|
public:
|
||||||
|
Config(/* args */);
|
||||||
|
~Config();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
219
src/contact_mgr.cc
Normal file
219
src/contact_mgr.cc
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "contact_mgr.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "wechat_function.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
namespace wxhelper {
|
||||||
|
ContactMgr::ContactMgr(DWORD base) : BaseMgr(base) {}
|
||||||
|
ContactMgr::~ContactMgr() {}
|
||||||
|
int ContactMgr::GetAllContact(vector<Contact> &vec) {
|
||||||
|
DWORD get_instance = base_addr_ + WX_CONTACT_MGR_OFFSET;
|
||||||
|
DWORD contact_get_list = base_addr_ + WX_CONTACT_GET_LIST_OFFSET;
|
||||||
|
DWORD *contact[3] = {0, 0, 0};
|
||||||
|
int success = 0;
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
CALL get_instance
|
||||||
|
LEA ECX,contact
|
||||||
|
PUSH ECX
|
||||||
|
MOV ECX,EAX
|
||||||
|
CALL contact_get_list
|
||||||
|
MOVZX EAX,AL
|
||||||
|
MOV success,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
DWORD start = (DWORD)contact[0];
|
||||||
|
DWORD end = (DWORD)contact[2];
|
||||||
|
while (start < end) {
|
||||||
|
Contact temp{0};
|
||||||
|
|
||||||
|
temp.wxid.ptr = *(wchar_t **)(start + 0x10);
|
||||||
|
temp.wxid.length = *(DWORD *)(start + 0x14);
|
||||||
|
temp.wxid.max_length = *(DWORD *)(start + 0x18);
|
||||||
|
|
||||||
|
temp.custom_account.ptr = *(wchar_t **)(start + 0x24);
|
||||||
|
temp.custom_account.length = *(DWORD *)(start + 0x28);
|
||||||
|
temp.custom_account.max_length = *(DWORD *)(start + 0x2C);
|
||||||
|
|
||||||
|
temp.encrypt_name.ptr = *(wchar_t **)(start + 0x6c);
|
||||||
|
temp.encrypt_name.length = *(DWORD *)(start + 0x70);
|
||||||
|
temp.encrypt_name.max_length = *(DWORD *)(start + 0x74);
|
||||||
|
|
||||||
|
temp.pinyin.ptr = *(wchar_t **)(start + 0xAC);
|
||||||
|
temp.pinyin.length = *(DWORD *)(start + 0xB0);
|
||||||
|
temp.pinyin.max_length = *(DWORD *)(start + 0xB4);
|
||||||
|
|
||||||
|
temp.pinyin_all.ptr = *(wchar_t **)(start + 0xC0);
|
||||||
|
temp.pinyin_all.length = *(DWORD *)(start + 0xC4);
|
||||||
|
temp.pinyin_all.max_length = *(DWORD *)(start + 0xC8);
|
||||||
|
|
||||||
|
temp.del_flag = *(DWORD *)(start + 0x4c);
|
||||||
|
temp.type = *(DWORD *)(start + 0x50);
|
||||||
|
temp.verify_flag = *(DWORD *)(start + 0x54);
|
||||||
|
vec.push_back(temp);
|
||||||
|
start += 0x438;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
int ContactMgr::DelContact(wchar_t *wxid) {
|
||||||
|
int success = -1;
|
||||||
|
WeChatString user_id(wxid);
|
||||||
|
DWORD id_ptr = (DWORD)&user_id;
|
||||||
|
DWORD sync_mgr_addr = base_addr_ + WX_SYNC_MGR_OFFSET;
|
||||||
|
DWORD set_id_addr = base_addr_ + WX_SET_VALUE_OFFSET;
|
||||||
|
DWORD del_contact_addr = base_addr_ + WX_DO_DEL_CONTACT_OFFSET;
|
||||||
|
int len = user_id.length;
|
||||||
|
wstring ws_wxid(wxid);
|
||||||
|
|
||||||
|
string id_cstr = Utils::WstringToUTF8(ws_wxid);
|
||||||
|
char id_[0x20] = {0};
|
||||||
|
memcpy(id_, id_cstr.c_str(), id_cstr.size() + 1);
|
||||||
|
char buff[0x10] = {0};
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
CALL sync_mgr_addr
|
||||||
|
MOV ECX,EAX
|
||||||
|
LEA EAX,buff
|
||||||
|
MOV [ECX + 4],EAX
|
||||||
|
LEA EAX,id_
|
||||||
|
Mov dword ptr[buff +0x4],EAX
|
||||||
|
CALL del_contact_addr
|
||||||
|
MOV success,EAX
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
wstring ContactMgr::GetContactOrChatRoomNickname(wchar_t *id) {
|
||||||
|
int success = -1;
|
||||||
|
char buff[0x440] = {0};
|
||||||
|
WeChatString pri(id);
|
||||||
|
DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET;
|
||||||
|
DWORD get_contact_addr = base_addr_ + WX_GET_CONTACT_OFFSET;
|
||||||
|
DWORD free_contact_addr = base_addr_ + WX_FREE_CONTACT_OFFSET;
|
||||||
|
wstring name = L"";
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
CALL contact_mgr_addr
|
||||||
|
LEA ECX,buff
|
||||||
|
PUSH ECX
|
||||||
|
LEA ECX,pri
|
||||||
|
PUSH ECX
|
||||||
|
MOV ECX,EAX
|
||||||
|
CALL get_contact_addr
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
name += READ_WSTRING(buff, 0x6C);
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
LEA ECX,buff
|
||||||
|
CALL free_contact_addr
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ContactMgr::AddFriendByWxid(wchar_t *wxid,wchar_t* msg) {
|
||||||
|
int success = -1;
|
||||||
|
DWORD contact_mgr_addr = base_addr_ + WX_CONTACT_MGR_OFFSET;
|
||||||
|
DWORD verify_msg_addr = base_addr_ + WX_VERIFY_MSG_OFFSET;
|
||||||
|
DWORD set_value_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||||
|
DWORD do_verify_user_addr = base_addr_ + WX_DO_VERIFY_USER_OFFSET;
|
||||||
|
DWORD fn1_addr = base_addr_ + 0x758720;
|
||||||
|
WeChatString user_id(wxid);
|
||||||
|
WeChatString w_msg(msg);
|
||||||
|
DWORD instance =0;
|
||||||
|
Unkown null_obj={0,0,0,0,0,0xF};
|
||||||
|
__asm{
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
CALL contact_mgr_addr
|
||||||
|
MOV dword ptr [instance],EAX
|
||||||
|
MOV EDI,0x6
|
||||||
|
MOV ESI,0
|
||||||
|
MOV EAX,0x2
|
||||||
|
SUB ESP,0x18
|
||||||
|
MOV EAX,ESP
|
||||||
|
MOV dword ptr ds:[EAX],0
|
||||||
|
MOV dword ptr ds:[EAX+0x14],0xF
|
||||||
|
MOV dword ptr ds:[EAX+0x10],0
|
||||||
|
MOV byte ptr ds:[EAX],0
|
||||||
|
SUB ESP,0x18
|
||||||
|
LEA EAX,null_obj
|
||||||
|
MOV ECX,ESP
|
||||||
|
PUSH EAX
|
||||||
|
CALL fn1_addr
|
||||||
|
PUSH 0x0
|
||||||
|
PUSH 0x6
|
||||||
|
MOV EAX,w_msg
|
||||||
|
|
||||||
|
SUB ESP,0x14
|
||||||
|
MOV ECX,ESP
|
||||||
|
PUSH -0x1
|
||||||
|
PUSH EAX
|
||||||
|
CALL verify_msg_addr
|
||||||
|
PUSH 0x2
|
||||||
|
LEA EAX,user_id
|
||||||
|
|
||||||
|
SUB ESP,0x14
|
||||||
|
MOV ECX,ESP
|
||||||
|
PUSH EAX
|
||||||
|
CALL set_value_addr
|
||||||
|
MOV ECX,dword ptr [instance]
|
||||||
|
CALL do_verify_user_addr
|
||||||
|
MOV success,EAX
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ContactMgr::VerifyApply(wchar_t *v3, wchar_t *v4){
|
||||||
|
int success = -1;
|
||||||
|
DWORD set_value_addr = base_addr_ + WX_INIT_CHAT_MSG_OFFSET;
|
||||||
|
DWORD verify_addr = base_addr_ + WX_VERIFY_OK_OFFSET;
|
||||||
|
DWORD new_helper_addr = base_addr_ + WX_NEW_ADD_FRIEND_HELPER_OFFSET;
|
||||||
|
DWORD free_helper_addr = base_addr_ + WX_FREE_ADD_FRIEND_HELPER_OFFSET;
|
||||||
|
|
||||||
|
WeChatString v4_str(v4);
|
||||||
|
WeChatString v3_str(v3);
|
||||||
|
char helper_obj[0x40] = {0};
|
||||||
|
char nullbuffer[0x3CC] = {0};
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
LEA ECX,helper_obj
|
||||||
|
CALL new_helper_addr
|
||||||
|
MOV ESI,0x0
|
||||||
|
MOV EDI,0x6
|
||||||
|
PUSH ESI
|
||||||
|
PUSH EDI
|
||||||
|
SUB ESP,0x14
|
||||||
|
MOV ECX,ESP
|
||||||
|
LEA EAX,v4_str
|
||||||
|
PUSH EAX
|
||||||
|
CALL set_value_addr
|
||||||
|
SUB ESP,0x8
|
||||||
|
PUSH 0x0
|
||||||
|
LEA EAX, nullbuffer
|
||||||
|
PUSH EAX
|
||||||
|
LEA EAX,v3_str
|
||||||
|
PUSH EAX
|
||||||
|
LEA ECX,helper_obj
|
||||||
|
CALL verify_addr
|
||||||
|
MOV success,EAX
|
||||||
|
LEA ECX,helper_obj
|
||||||
|
CALL free_helper_addr
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
} // namespace wxhelper
|
21
src/contact_mgr.h
Normal file
21
src/contact_mgr.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef WXHELPER_CONTACT_MGR_H_
|
||||||
|
#define WXHELPER_CONTACT_MGR_H_
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "base_mgr.h"
|
||||||
|
#include "wechat_function.h"
|
||||||
|
namespace wxhelper {
|
||||||
|
class ContactMgr : public BaseMgr {
|
||||||
|
public:
|
||||||
|
explicit ContactMgr(DWORD base);
|
||||||
|
~ContactMgr();
|
||||||
|
int GetAllContact(std::vector<Contact>& vec);
|
||||||
|
int DelContact(wchar_t* wxid);
|
||||||
|
std::wstring GetContactOrChatRoomNickname(wchar_t* id);
|
||||||
|
int AddFriendByWxid(wchar_t* wxid,wchar_t* msg);
|
||||||
|
int VerifyApply(wchar_t *v3, wchar_t *v4);
|
||||||
|
};
|
||||||
|
} // namespace wxhelper
|
||||||
|
|
||||||
|
#endif;
|
540
src/db.cc
Normal file
540
src/db.cc
Normal file
@ -0,0 +1,540 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "db.h"
|
||||||
|
|
||||||
|
#include "base64.h"
|
||||||
|
#include "easylogging++.h"
|
||||||
|
|
||||||
|
#include "wechat_function.h"
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
namespace wxhelper {
|
||||||
|
|
||||||
|
void DB::init(DWORD base) {
|
||||||
|
base_addr_ = base;
|
||||||
|
dbmap_ = {};
|
||||||
|
dbs_ = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeResult(vector<vector<SqlResult>> &data) {
|
||||||
|
if (data.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i < data.size(); i++) {
|
||||||
|
for (unsigned j = 0; j < data[i].size(); j++) {
|
||||||
|
SqlResult *sr = (SqlResult *)&data[i][j];
|
||||||
|
if (sr->column_name) {
|
||||||
|
delete[] sr->column_name;
|
||||||
|
sr->column_name = NULL;
|
||||||
|
}
|
||||||
|
if (sr->content) {
|
||||||
|
delete[] sr->content;
|
||||||
|
sr->content = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data[i].clear();
|
||||||
|
}
|
||||||
|
data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int DB::SelectDataInner(DWORD db, const char *sql,
|
||||||
|
vector<vector<SqlResult>> &data) {
|
||||||
|
Sqlite3_prepare p_Sqlite3_prepare =
|
||||||
|
(Sqlite3_prepare)(base_addr_ + SQLITE3_PREPARE_OFFSET);
|
||||||
|
Sqlite3_step p_Sqlite3_step =
|
||||||
|
(Sqlite3_step)(base_addr_ + SQLITE3_STEP_OFFSET);
|
||||||
|
Sqlite3_column_count p_Sqlite3_column_count =
|
||||||
|
(Sqlite3_column_count)(base_addr_ + SQLITE3_COLUMN_COUNT_OFFSET);
|
||||||
|
Sqlite3_column_name p_Sqlite3_column_name =
|
||||||
|
(Sqlite3_column_name)(base_addr_ + SQLITE3_COLUMN_NAME_OFFSET);
|
||||||
|
Sqlite3_column_type p_Sqlite3_column_type =
|
||||||
|
(Sqlite3_column_type)(base_addr_ + SQLITE3_COLUMN_TYPE_OFFSET);
|
||||||
|
Sqlite3_column_blob p_Sqlite3_column_blob =
|
||||||
|
(Sqlite3_column_blob)(base_addr_ + SQLITE3_COLUMN_BLOB_OFFSET);
|
||||||
|
Sqlite3_column_bytes p_Sqlite3_column_bytes =
|
||||||
|
(Sqlite3_column_bytes)(base_addr_ + SQLITE3_COLUMN_BYTES_OFFSET);
|
||||||
|
Sqlite3_finalize p_Sqlite3_finalize =
|
||||||
|
(Sqlite3_finalize)(base_addr_ + SQLITE3_FINALIZE_OFFSET);
|
||||||
|
DWORD *stmt;
|
||||||
|
int rc = p_Sqlite3_prepare(db, sql, -1, &stmt, 0);
|
||||||
|
if (rc != SQLITE_OK) return NULL;
|
||||||
|
while (p_Sqlite3_step(stmt) == SQLITE_ROW) {
|
||||||
|
int col_count = p_Sqlite3_column_count(stmt);
|
||||||
|
vector<SqlResult> tempStruct;
|
||||||
|
for (int i = 0; i < col_count; i++) {
|
||||||
|
SqlResult temp = {0};
|
||||||
|
const char *ColName = p_Sqlite3_column_name(stmt, i);
|
||||||
|
int nType = p_Sqlite3_column_type(stmt, i);
|
||||||
|
const void *pReadBlobData = p_Sqlite3_column_blob(stmt, i);
|
||||||
|
int nLength = p_Sqlite3_column_bytes(stmt, i);
|
||||||
|
temp.column_name = new char[strlen(ColName) + 1];
|
||||||
|
memcpy(temp.column_name, ColName, strlen(ColName) + 1);
|
||||||
|
temp.column_name_len = strlen(ColName);
|
||||||
|
temp.content_len = nLength;
|
||||||
|
switch (nType) {
|
||||||
|
case SQLITE_BLOB: {
|
||||||
|
temp.content = new char[nLength];
|
||||||
|
memcpy(temp.content, pReadBlobData, nLength);
|
||||||
|
temp.is_blob = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
if (nLength != 0) {
|
||||||
|
temp.content = new char[nLength + 1];
|
||||||
|
memcpy(temp.content, pReadBlobData, nLength + 1);
|
||||||
|
} else {
|
||||||
|
temp.content = new char[2];
|
||||||
|
ZeroMemory(temp.content, 2);
|
||||||
|
}
|
||||||
|
temp.is_blob = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tempStruct.push_back(temp);
|
||||||
|
}
|
||||||
|
data.push_back(tempStruct);
|
||||||
|
}
|
||||||
|
p_Sqlite3_finalize(stmt);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DB::Select(DWORD db_hanle, const char *sql,
|
||||||
|
vector<vector<string>> &query_result) {
|
||||||
|
vector<vector<SqlResult>> data;
|
||||||
|
int status = SelectDataInner(db_hanle, sql, data);
|
||||||
|
if (status == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (data.size() == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
vector<string> index;
|
||||||
|
for (size_t i = 0; i < data[0].size(); i++) {
|
||||||
|
index.push_back(data[0][i].column_name);
|
||||||
|
}
|
||||||
|
query_result.push_back(index);
|
||||||
|
|
||||||
|
for (auto it : data) {
|
||||||
|
vector<string> item;
|
||||||
|
for (size_t i = 0; i < it.size(); i++) {
|
||||||
|
if (!it[i].is_blob) {
|
||||||
|
string content(it[i].content);
|
||||||
|
item.push_back(content);
|
||||||
|
} else {
|
||||||
|
string b64_str =
|
||||||
|
base64_encode((BYTE *)it[i].content, it[i].content_len);
|
||||||
|
item.push_back(b64_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
query_result.push_back(item);
|
||||||
|
}
|
||||||
|
FreeResult(data);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SelectDbInfo(void *data, int argc, char **argv, char **name) {
|
||||||
|
vector<SqlResult> result;
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
SqlResult temp = {0};
|
||||||
|
temp.column_name = new char[strlen(name[i]) + 1];
|
||||||
|
memcpy(temp.column_name, name[i], strlen(name[i]) + 1);
|
||||||
|
temp.column_name_len = strlen(name[i]);
|
||||||
|
if (argv[i]) {
|
||||||
|
temp.content = new char[strlen(argv[i]) + 1];
|
||||||
|
memcpy(temp.content, argv[i], strlen(argv[i]) + 1);
|
||||||
|
temp.content_len = strlen(argv[i]);
|
||||||
|
} else {
|
||||||
|
temp.content = new char[2];
|
||||||
|
ZeroMemory(temp.content, 2);
|
||||||
|
temp.content_len = 0;
|
||||||
|
}
|
||||||
|
result.push_back(temp);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DB::ExecuteSQL(DWORD db, const char *sql, DWORD callback, void *data) {
|
||||||
|
DWORD sqlite3_exec_addr = base_addr_ + SQLITE3_EXEC_OFFSET;
|
||||||
|
Sqlite3_exec fn_sqlite3_exec = (Sqlite3_exec)sqlite3_exec_addr;
|
||||||
|
int status = fn_sqlite3_exec(db, sql, (Sqlite3_callback)callback, data, 0);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetDbInfo(void *data, int argc, char **argv, char **name) {
|
||||||
|
DatabaseInfo *pdata = (DatabaseInfo *)data;
|
||||||
|
TableInfo tb = {0};
|
||||||
|
if (argv[1]) {
|
||||||
|
tb.name = new char[strlen(argv[1]) + 1];
|
||||||
|
memcpy(tb.name, argv[1], strlen(argv[1]) + 1);
|
||||||
|
} else {
|
||||||
|
tb.name = (char *)"NULL";
|
||||||
|
}
|
||||||
|
if (argv[2]) {
|
||||||
|
tb.table_name = new char[strlen(argv[2]) + 1];
|
||||||
|
memcpy(tb.table_name, argv[2], strlen(argv[2]) + 1);
|
||||||
|
} else {
|
||||||
|
tb.table_name = (char *)"NULL";
|
||||||
|
}
|
||||||
|
if (argv[3]) {
|
||||||
|
tb.rootpage = new char[strlen(argv[3]) + 1];
|
||||||
|
memcpy(tb.rootpage, argv[3], strlen(argv[3]) + 1);
|
||||||
|
} else {
|
||||||
|
tb.rootpage = (char *)"NULL";
|
||||||
|
}
|
||||||
|
if (argv[4]) {
|
||||||
|
tb.sql = new char[strlen(argv[4]) + 1];
|
||||||
|
memcpy(tb.sql, argv[4], strlen(argv[4]) + 1);
|
||||||
|
} else {
|
||||||
|
tb.sql = (char *)"NULL";
|
||||||
|
}
|
||||||
|
tb.name_len = strlen(tb.name);
|
||||||
|
tb.table_name_len = strlen(tb.table_name);
|
||||||
|
tb.sql_len = strlen(tb.sql);
|
||||||
|
tb.rootpage_len = strlen(tb.rootpage);
|
||||||
|
pdata->tables.push_back(tb);
|
||||||
|
pdata->count = pdata->tables.size();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<void *> DB::GetDbHandles() {
|
||||||
|
dbs_.clear();
|
||||||
|
dbmap_.clear();
|
||||||
|
DWORD p_contact_addr = *(DWORD *)(base_addr_ + CONTACT_G_PINSTANCE_OFFSET);
|
||||||
|
DWORD micro_msg_db_addr = *(DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET);
|
||||||
|
DWORD chat_msg_db_addr = *(DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET);
|
||||||
|
DWORD misc_db_addr = *(DWORD *)(p_contact_addr + DB_MISC_OFFSET);
|
||||||
|
DWORD emotion_db_addr = *(DWORD *)(p_contact_addr + DB_EMOTION_OFFSET);
|
||||||
|
DWORD media_db_addr = *(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET);
|
||||||
|
DWORD bizchat_msg_db_addr =
|
||||||
|
*(DWORD *)(p_contact_addr + DB_BIZCHAT_MSG_OFFSET);
|
||||||
|
DWORD function_msg_db_addr =
|
||||||
|
*(DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET);
|
||||||
|
|
||||||
|
// microMsg.db
|
||||||
|
DatabaseInfo micro_msg_db{0};
|
||||||
|
micro_msg_db.db_name = (wchar_t *)(*(
|
||||||
|
DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET));
|
||||||
|
micro_msg_db.db_name_len =
|
||||||
|
*(DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||||
|
micro_msg_db.handle = micro_msg_db_addr;
|
||||||
|
ExecuteSQL(micro_msg_db_addr,
|
||||||
|
"select * from sqlite_master where type=\"table\";",
|
||||||
|
(DWORD)GetDbInfo, µ_msg_db);
|
||||||
|
dbs_.push_back(micro_msg_db);
|
||||||
|
wstring micro_msg_name = wstring((wchar_t *)(*(
|
||||||
|
DWORD *)(p_contact_addr + DB_MICRO_MSG_OFFSET + DB_NAME_OFFSET)));
|
||||||
|
dbmap_[micro_msg_name] = micro_msg_db;
|
||||||
|
|
||||||
|
// chatMsg.db
|
||||||
|
DatabaseInfo chat_msg_db{0};
|
||||||
|
chat_msg_db.db_name = (wchar_t *)(*(
|
||||||
|
DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET));
|
||||||
|
chat_msg_db.db_name_len =
|
||||||
|
*(DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||||
|
chat_msg_db.handle = chat_msg_db_addr;
|
||||||
|
ExecuteSQL(chat_msg_db_addr,
|
||||||
|
"select * from sqlite_master where type=\"table\";",
|
||||||
|
(DWORD)GetDbInfo, &chat_msg_db);
|
||||||
|
dbs_.push_back(chat_msg_db);
|
||||||
|
wstring chat_msg_name = wstring((wchar_t *)(*(
|
||||||
|
DWORD *)(p_contact_addr + DB_CHAT_MSG_OFFSET + DB_NAME_OFFSET)));
|
||||||
|
dbmap_[chat_msg_name] = chat_msg_db;
|
||||||
|
|
||||||
|
// misc.db
|
||||||
|
DatabaseInfo misc_db{0};
|
||||||
|
misc_db.db_name =
|
||||||
|
(wchar_t *)(*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET));
|
||||||
|
misc_db.db_name_len =
|
||||||
|
*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||||
|
misc_db.handle = misc_db_addr;
|
||||||
|
ExecuteSQL(misc_db_addr, "select * from sqlite_master where type=\"table\";",
|
||||||
|
(DWORD)GetDbInfo, &misc_db);
|
||||||
|
dbs_.push_back(misc_db);
|
||||||
|
wstring misc_name = wstring((
|
||||||
|
wchar_t *)(*(DWORD *)(p_contact_addr + DB_MISC_OFFSET + DB_NAME_OFFSET)));
|
||||||
|
dbmap_[misc_name] = misc_db;
|
||||||
|
|
||||||
|
// emotion.db
|
||||||
|
DatabaseInfo emotion_db{0};
|
||||||
|
emotion_db.db_name = (wchar_t *)(*(
|
||||||
|
DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET));
|
||||||
|
emotion_db.db_name_len =
|
||||||
|
*(DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||||
|
emotion_db.handle = emotion_db_addr;
|
||||||
|
ExecuteSQL(emotion_db_addr,
|
||||||
|
"select * from sqlite_master where type=\"table\";",
|
||||||
|
(DWORD)GetDbInfo, &emotion_db);
|
||||||
|
dbs_.push_back(emotion_db);
|
||||||
|
wstring emotion_name = wstring((wchar_t *)(*(
|
||||||
|
DWORD *)(p_contact_addr + DB_EMOTION_OFFSET + DB_NAME_OFFSET)));
|
||||||
|
dbmap_[emotion_name] = emotion_db;
|
||||||
|
|
||||||
|
// media.db
|
||||||
|
DatabaseInfo media_db{0};
|
||||||
|
media_db.db_name = (wchar_t *)(*(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET +
|
||||||
|
DB_NAME_OFFSET));
|
||||||
|
media_db.db_name_len =
|
||||||
|
*(DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||||
|
media_db.handle = media_db_addr;
|
||||||
|
ExecuteSQL(media_db_addr, "select * from sqlite_master where type=\"table\";",
|
||||||
|
(DWORD)GetDbInfo, &media_db);
|
||||||
|
dbs_.push_back(media_db);
|
||||||
|
wstring media_name = wstring((wchar_t *)(*(
|
||||||
|
DWORD *)(p_contact_addr + DB_MEDIA_OFFSET + DB_NAME_OFFSET)));
|
||||||
|
dbmap_[media_name] = media_db;
|
||||||
|
|
||||||
|
// functionMsg.db
|
||||||
|
DatabaseInfo function_msg_db{0};
|
||||||
|
function_msg_db.db_name = (wchar_t *)(*(
|
||||||
|
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET));
|
||||||
|
function_msg_db.db_name_len = *(
|
||||||
|
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET + 0x4);
|
||||||
|
function_msg_db.handle = function_msg_db_addr;
|
||||||
|
ExecuteSQL(function_msg_db_addr,
|
||||||
|
"select * from sqlite_master where type=\"table\";",
|
||||||
|
(DWORD)GetDbInfo, &function_msg_db);
|
||||||
|
dbs_.push_back(function_msg_db);
|
||||||
|
wstring function_msg_name = wstring((wchar_t *)(*(
|
||||||
|
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET)));
|
||||||
|
dbmap_[function_msg_name] = function_msg_db;
|
||||||
|
|
||||||
|
if (bizchat_msg_db_addr) {
|
||||||
|
// functionMsg.db maybe null
|
||||||
|
DatabaseInfo bizchat_msg_db{0};
|
||||||
|
bizchat_msg_db.db_name = (wchar_t *)(*(
|
||||||
|
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET));
|
||||||
|
bizchat_msg_db.db_name_len =
|
||||||
|
*(DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET +
|
||||||
|
0x4);
|
||||||
|
bizchat_msg_db.handle = bizchat_msg_db_addr;
|
||||||
|
ExecuteSQL(bizchat_msg_db_addr,
|
||||||
|
"select * from sqlite_master where type=\"table\";",
|
||||||
|
(DWORD)GetDbInfo, &bizchat_msg_db);
|
||||||
|
dbs_.push_back(bizchat_msg_db);
|
||||||
|
wstring bizchat_msg_name = wstring((wchar_t *)(*(
|
||||||
|
DWORD *)(p_contact_addr + DB_FUNCTION_MSG_OFFSET + DB_NAME_OFFSET)));
|
||||||
|
dbmap_[bizchat_msg_name] = bizchat_msg_db;
|
||||||
|
}
|
||||||
|
// Storage
|
||||||
|
DWORD storage_start = *(DWORD *)(p_contact_addr + STORAGE_START_OFFSET);
|
||||||
|
DWORD storage_end = *(DWORD *)(p_contact_addr + STORAGE_END_OFFSET);
|
||||||
|
|
||||||
|
// do {
|
||||||
|
// DWORD vtable_ptr = *(DWORD *)(storage_start);
|
||||||
|
|
||||||
|
// if(vtable_ptr == base + OP_LOG_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + CHAT_MSG_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + CHAT_CR_MSG_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + SESSION_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + APP_INFO_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + HEAD_IMG_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + HEAD_IMG_URL_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + BIZ_INFO_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + TICKET_INFO_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + CHAT_ROOM_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + CHAT_ROOM_INFO_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + MEDIA_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + NAME_2_ID_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + EMOTION_PACKAGE_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + EMOTION_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + BUFINFO_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + CUSTOM_EMOTION_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + DEL_SESSIONINFO_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + FUNCTION_MSG_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + FUNCTION_MSG_TASK_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }else if(vtable_ptr == base + REVOKE_MSG_STORAGE_VFTABLE){
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// storage_start = storage_start + 0x4;
|
||||||
|
// } while (storage_start != storage_end);
|
||||||
|
|
||||||
|
DWORD multi_db_mgr_addr = base_addr_ + MULTI_DB_MSG_MGR_OFFSET;
|
||||||
|
DWORD public_msg_mgr_addr = base_addr_ + PUBLIC_MSG_MGR_OFFSET;
|
||||||
|
DWORD favorite_storage_mgr_addr = base_addr_ + FAVORITE_STORAGE_MGR_OFFSET;
|
||||||
|
DWORD fts_favorite_mgr_addr = base_addr_ + FTS_FAVORITE_MGR_OFFSET;
|
||||||
|
|
||||||
|
// MsgX.db
|
||||||
|
DWORD wrap_ptr = *(DWORD *)(multi_db_mgr_addr);
|
||||||
|
DWORD db_num = *(DWORD *)(wrap_ptr + 0x30);
|
||||||
|
DWORD current_db_num = *(DWORD *)(wrap_ptr + 0x38);
|
||||||
|
DWORD begin_ptr = *(DWORD *)(wrap_ptr + 0x2c);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < current_db_num; i++) {
|
||||||
|
DWORD next_addr = begin_ptr + i * 0x4;
|
||||||
|
DWORD db_addr = *(DWORD *)next_addr;
|
||||||
|
if (db_addr) {
|
||||||
|
DWORD msg0_db_addr = *(DWORD *)(db_addr + 0x60);
|
||||||
|
DatabaseInfo msg0_db{0};
|
||||||
|
msg0_db.db_name = (wchar_t *)(*(DWORD *)(db_addr));
|
||||||
|
msg0_db.db_name_len = *(DWORD *)(db_addr + 0x4);
|
||||||
|
msg0_db.handle = msg0_db_addr;
|
||||||
|
msg0_db.extrainfo = *(DWORD *)(*(DWORD *)(db_addr + 0x18) + 0x144);
|
||||||
|
ExecuteSQL(msg0_db_addr,
|
||||||
|
"select * from sqlite_master where type=\"table\";",
|
||||||
|
(DWORD)GetDbInfo, &msg0_db);
|
||||||
|
dbs_.push_back(msg0_db);
|
||||||
|
wstring msg_db_name = wstring((wchar_t *)(*(DWORD *)(db_addr)));
|
||||||
|
dbmap_[msg_db_name] = msg0_db;
|
||||||
|
|
||||||
|
// BufInfoStorage
|
||||||
|
DWORD buf_info_addr = *(DWORD *)(db_addr + 0x14);
|
||||||
|
|
||||||
|
DWORD buf_info_handle = *(DWORD *)(buf_info_addr + 0x38);
|
||||||
|
DatabaseInfo media_msg0_db{0};
|
||||||
|
media_msg0_db.db_name = (wchar_t *)(*(DWORD *)(buf_info_addr + 0x4C));
|
||||||
|
media_msg0_db.db_name_len = *(DWORD *)(buf_info_addr + 0x50);
|
||||||
|
media_msg0_db.handle = buf_info_handle;
|
||||||
|
ExecuteSQL(buf_info_handle,
|
||||||
|
"select * from sqlite_master where type=\"table\";",
|
||||||
|
(DWORD)GetDbInfo, &media_msg0_db);
|
||||||
|
dbs_.push_back(media_msg0_db);
|
||||||
|
wstring media_msg_db_name =
|
||||||
|
wstring((wchar_t *)(*(DWORD *)(buf_info_addr + 0x4C)));
|
||||||
|
dbmap_[media_msg_db_name] = media_msg0_db;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// publicMsg.db
|
||||||
|
DWORD public_msg_ptr = *(DWORD *)(*(DWORD *)(public_msg_mgr_addr) + 0x8);
|
||||||
|
if (public_msg_ptr) {
|
||||||
|
DWORD public_msg_db_addr = *(DWORD *)(public_msg_ptr + 0x38);
|
||||||
|
DatabaseInfo public_msg_db{0};
|
||||||
|
public_msg_db.db_name = (wchar_t *)(*(DWORD *)(public_msg_ptr + 0x4C));
|
||||||
|
public_msg_db.db_name_len = *(DWORD *)(public_msg_ptr + 0x50);
|
||||||
|
public_msg_db.handle = public_msg_db_addr;
|
||||||
|
ExecuteSQL(public_msg_db_addr,
|
||||||
|
"select * from sqlite_master where type=\"table\";",
|
||||||
|
(DWORD)GetDbInfo, &public_msg_db);
|
||||||
|
dbs_.push_back(public_msg_db);
|
||||||
|
wstring public_msg_db_name =
|
||||||
|
wstring((wchar_t *)(*(DWORD *)(public_msg_ptr + 0x4C)));
|
||||||
|
dbmap_[public_msg_db_name] = public_msg_db;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Favorite.db
|
||||||
|
DWORD favItems_ptr =
|
||||||
|
*(DWORD *)(*(DWORD *)(*(DWORD *)(favorite_storage_mgr_addr) + 0x8) + 0x4);
|
||||||
|
if (favItems_ptr) {
|
||||||
|
DWORD favorite_db_addr = *(DWORD *)(favItems_ptr + 0x38);
|
||||||
|
DatabaseInfo favorite_db{0};
|
||||||
|
favorite_db.db_name = (wchar_t *)(*(DWORD *)(favItems_ptr + 0x4C));
|
||||||
|
favorite_db.db_name_len = *(DWORD *)(favItems_ptr + 0x50);
|
||||||
|
favorite_db.handle = favorite_db_addr;
|
||||||
|
ExecuteSQL(favorite_db_addr,
|
||||||
|
"select * from sqlite_master where type=\"table\";",
|
||||||
|
(DWORD)GetDbInfo, &favorite_db);
|
||||||
|
dbs_.push_back(favorite_db);
|
||||||
|
wstring public_msg_db_name =
|
||||||
|
wstring((wchar_t *)(*(DWORD *)(favItems_ptr + 0x4C)));
|
||||||
|
dbmap_[public_msg_db_name] = favorite_db;
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseInfo db_end = {0};
|
||||||
|
dbs_.push_back(db_end);
|
||||||
|
#ifdef _DEBUG
|
||||||
|
for (unsigned int i = 0; i < dbs_.size() - 1; i++) {
|
||||||
|
LOG(INFO) << "dbname =" << dbs_[i].db_name;
|
||||||
|
LOG(INFO) << "handle =" << dbs_[i].handle;
|
||||||
|
LOG(INFO) << "table_count =" << dbs_[i].tables.size();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
vector<void *> ret_array;
|
||||||
|
for (unsigned int i = 0; i < dbs_.size() - 1; i++)
|
||||||
|
ret_array.push_back(&dbs_[i]);
|
||||||
|
return ret_array;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD DB::GetDbHandleByDbName(wchar_t *dbname) {
|
||||||
|
if (dbmap_.size() == 0) {
|
||||||
|
GetDbHandles();
|
||||||
|
}
|
||||||
|
if (dbmap_.find(dbname) != dbmap_.end()) {
|
||||||
|
return dbmap_[dbname].handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int DB::GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex) {
|
||||||
|
char sql[260] = {0};
|
||||||
|
sprintf_s(sql, "select localId from MSG where MsgSvrID=%llu;", msgid);
|
||||||
|
wchar_t dbname[20] = {0};
|
||||||
|
for (int i = 0;; i++) {
|
||||||
|
swprintf_s(dbname, L"MSG%d.db", i);
|
||||||
|
DWORD handle = GetDbHandleByDbName(dbname);
|
||||||
|
if (handle == 0) {
|
||||||
|
LOG(INFO) << "MSG db handle is null";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
vector<vector<string>> result;
|
||||||
|
int ret = Select(handle, (const char *)sql, result);
|
||||||
|
if (result.size() == 0) continue;
|
||||||
|
dbIndex = dbmap_[dbname].extrainfo;
|
||||||
|
return stoi(result[1][0]);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<string> DB::GetChatMsgByMsgId(ULONG64 msgid) {
|
||||||
|
char sql[260] = {0};
|
||||||
|
sprintf_s(sql,
|
||||||
|
"select "
|
||||||
|
"localId,TalkerId,MsgSvrID,Type,SubType,IsSender,CreateTime,"
|
||||||
|
"Sequence,StatusEx,FlagEx,Status,MsgServerSeq,MsgSequence,"
|
||||||
|
"StrTalker,StrContent,BytesExtra from MSG where MsgSvrID=%llu;",
|
||||||
|
msgid);
|
||||||
|
wchar_t dbname[20] = {0};
|
||||||
|
for (int i = 0;; i++) {
|
||||||
|
swprintf_s(dbname, L"MSG%d.db", i);
|
||||||
|
DWORD handle = GetDbHandleByDbName(dbname);
|
||||||
|
if (handle == 0) {
|
||||||
|
LOG(INFO) << "MSG db handle is null";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
vector<vector<string>> result;
|
||||||
|
int ret = Select(handle, (const char *)sql, result);
|
||||||
|
if (result.size() == 0) continue;
|
||||||
|
return result[1];
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DB::GetVoiceBuffByMsgId(ULONG64 msgid) {
|
||||||
|
char sql[260] = {0};
|
||||||
|
sprintf_s(sql, "SELECT Buf from Media WHERE Reserved0=%llu;", msgid);
|
||||||
|
wchar_t dbname[20] = {0};
|
||||||
|
for (int i = 0;; i++) {
|
||||||
|
swprintf_s(dbname, L"MediaMSG%d.db", i);
|
||||||
|
DWORD handle = GetDbHandleByDbName(dbname);
|
||||||
|
if (handle == 0) {
|
||||||
|
LOG(INFO) << "Media db handle is null";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
vector<vector<string>> result;
|
||||||
|
int ret = Select(handle, (const char *)sql, result);
|
||||||
|
if (result.size() == 0) continue;
|
||||||
|
return result[1][0];
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
} // namespace wxhelper
|
38
src/db.h
Normal file
38
src/db.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef WXHELPER_DB_H_
|
||||||
|
#define WXHELPER_DB_H_
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "base_mgr.h"
|
||||||
|
#include "wechat_function.h"
|
||||||
|
#include "windows.h"
|
||||||
|
#include "singleton.h"
|
||||||
|
namespace wxhelper {
|
||||||
|
class DB :public Singleton<DB>{
|
||||||
|
public:
|
||||||
|
void init(DWORD base);
|
||||||
|
int ExecuteSQL(DWORD db, const char *sql, DWORD callback, void *data);
|
||||||
|
|
||||||
|
int Select(DWORD db_hanle, const char *sql,
|
||||||
|
std::vector<std::vector<std::string>> &query_result);
|
||||||
|
|
||||||
|
std::vector<void *> GetDbHandles();
|
||||||
|
DWORD GetDbHandleByDbName(wchar_t *dbname);
|
||||||
|
unsigned int GetLocalIdByMsgId(ULONG64 msgid, int &dbIndex);
|
||||||
|
std::vector<std::string> GetChatMsgByMsgId(ULONG64 msgid);
|
||||||
|
|
||||||
|
std::string GetVoiceBuffByMsgId(ULONG64 msgid);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int SelectDataInner(DWORD db, const char *sql,
|
||||||
|
std::vector<std::vector<SqlResult>> &data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::wstring, DatabaseInfo> dbmap_;
|
||||||
|
std::vector<DatabaseInfo> dbs_;
|
||||||
|
DWORD base_addr_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace wxhelper
|
||||||
|
|
||||||
|
#endif
|
32
src/dllMain.cc
Normal file
32
src/dllMain.cc
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "hide_module.h"
|
||||||
|
#include "global_context.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace wxhelper;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call,
|
||||||
|
LPVOID lpReserved) {
|
||||||
|
switch (ul_reason_for_call) {
|
||||||
|
case DLL_PROCESS_ATTACH: {
|
||||||
|
DisableThreadLibraryCalls(hModule);
|
||||||
|
GlobalContext::GetInstance().initialize(hModule);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DLL_THREAD_ATTACH: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DLL_THREAD_DETACH: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DLL_PROCESS_DETACH: {
|
||||||
|
GlobalContext::GetInstance().finally();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
3120
src/easylogging++.cc
Normal file
3120
src/easylogging++.cc
Normal file
File diff suppressed because it is too large
Load Diff
4576
src/easylogging++.h
Normal file
4576
src/easylogging++.h
Normal file
File diff suppressed because it is too large
Load Diff
38
src/global_context.cc
Normal file
38
src/global_context.cc
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "global_context.h"
|
||||||
|
#include "http_server.h"
|
||||||
|
#include "easylogging++.h"
|
||||||
|
#include "hooks.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace wxhelper {
|
||||||
|
|
||||||
|
void GlobalContext::initialize(HMODULE module) {
|
||||||
|
module_ = module;
|
||||||
|
DWORD base = Utils::GetWeChatWinBase();
|
||||||
|
config.emplace();
|
||||||
|
log.emplace();
|
||||||
|
log->initialize();
|
||||||
|
hide_module.emplace();
|
||||||
|
#ifndef _DEBUG
|
||||||
|
hide_module->Hide(module_);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HttpServer::GetInstance().Init(19088);
|
||||||
|
HttpServer::GetInstance().HttpStart();
|
||||||
|
DB::GetInstance().init(base);
|
||||||
|
contact_mgr.emplace(ContactMgr{base});
|
||||||
|
misc_mgr.emplace(MiscMgr{base});
|
||||||
|
send_mgr.emplace(SendMessageMgr{base});
|
||||||
|
account_mgr.emplace(AccountMgr{base});
|
||||||
|
chat_room_mgr.emplace(ChatRoomMgr{base});
|
||||||
|
sns_mgr.emplace(SNSMgr{base});
|
||||||
|
}
|
||||||
|
|
||||||
|
void GlobalContext::finally() {
|
||||||
|
HttpServer::GetInstance().HttpClose();
|
||||||
|
hooks::UnHookLog();
|
||||||
|
hooks::UnHookRecvMsg();
|
||||||
|
hooks::UnHookSearchContact();
|
||||||
|
}
|
||||||
|
} // namespace wxhelper
|
43
src/global_context.h
Normal file
43
src/global_context.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef GLOBAL_CONTEXT_H_
|
||||||
|
#define GLOBAL_CONTEXT_H_
|
||||||
|
#include "account_mgr.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "contact_mgr.h"
|
||||||
|
#include "db.h"
|
||||||
|
#include "hide_module.h"
|
||||||
|
#include "http_server.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "misc_mgr.h"
|
||||||
|
#include "send_message_mgr.h"
|
||||||
|
#include "chat_room_mgr.h"
|
||||||
|
#include "sns_mgr.h"
|
||||||
|
#include "singleton.h"
|
||||||
|
|
||||||
|
namespace wxhelper {
|
||||||
|
|
||||||
|
enum class GlobalContextState { NOT_INITIALIZED, INITIALIZING, INITIALIZED };
|
||||||
|
|
||||||
|
class GlobalContext :public Singleton<GlobalContext>{
|
||||||
|
public:
|
||||||
|
void initialize(HMODULE module);
|
||||||
|
void finally();
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::optional<Config> config;
|
||||||
|
std::optional<HideModule> hide_module;
|
||||||
|
std::optional<Log> log;
|
||||||
|
std::optional<ContactMgr> contact_mgr;
|
||||||
|
std::optional<MiscMgr> misc_mgr;
|
||||||
|
std::optional<SendMessageMgr> send_mgr;
|
||||||
|
std::optional<AccountMgr> account_mgr;
|
||||||
|
std::optional<ChatRoomMgr> chat_room_mgr;
|
||||||
|
std::optional<SNSMgr> sns_mgr;
|
||||||
|
|
||||||
|
GlobalContextState state = GlobalContextState::INITIALIZED;
|
||||||
|
|
||||||
|
private:
|
||||||
|
HMODULE module_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace wxhelper
|
||||||
|
#endif
|
10
src/handler.h
Normal file
10
src/handler.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef WXHELPER_HANDLER_H_
|
||||||
|
#define WXHELPER_HANDLER_H_
|
||||||
|
#include <mongoose.h>
|
||||||
|
namespace wxhelper {
|
||||||
|
class Handler {
|
||||||
|
public:
|
||||||
|
virtual void HandlerRequest(struct mg_connection *c, void *ev_data) = 0;
|
||||||
|
};
|
||||||
|
} // namespace wxhelper
|
||||||
|
#endif
|
64
src/hide_module.cc
Normal file
64
src/hide_module.cc
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "hide_module.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace wxhelper {
|
||||||
|
|
||||||
|
void HideModule::Hide(const char* module_name) {
|
||||||
|
HMODULE hMod = ::GetModuleHandleA(module_name);
|
||||||
|
PLIST_ENTRY Head, Cur;
|
||||||
|
PPEB_LDR_DATA ldr;
|
||||||
|
PLDR_MODULE ldm;
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
mov eax, fs: [0x30]
|
||||||
|
mov ecx, [eax + 0x0c]
|
||||||
|
mov ldr, ecx
|
||||||
|
}
|
||||||
|
Head = &(ldr->InLoadOrderModuleList);
|
||||||
|
Cur = Head->Flink;
|
||||||
|
do {
|
||||||
|
ldm = CONTAINING_RECORD(Cur, LDR_MODULE, InLoadOrderModuleList);
|
||||||
|
if (hMod == ldm->BaseAddress) {
|
||||||
|
ldm->InLoadOrderModuleList.Blink->Flink =
|
||||||
|
ldm->InLoadOrderModuleList.Flink;
|
||||||
|
ldm->InLoadOrderModuleList.Flink->Blink =
|
||||||
|
ldm->InLoadOrderModuleList.Blink;
|
||||||
|
ldm->InInitializationOrderModuleList.Blink->Flink =
|
||||||
|
ldm->InInitializationOrderModuleList.Flink;
|
||||||
|
ldm->InInitializationOrderModuleList.Flink->Blink =
|
||||||
|
ldm->InInitializationOrderModuleList.Blink;
|
||||||
|
ldm->InMemoryOrderModuleList.Blink->Flink =
|
||||||
|
ldm->InMemoryOrderModuleList.Flink;
|
||||||
|
ldm->InMemoryOrderModuleList.Flink->Blink =
|
||||||
|
ldm->InMemoryOrderModuleList.Blink;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Cur = Cur->Flink;
|
||||||
|
} while (Head != Cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HideModule::Hide(HMODULE module) {
|
||||||
|
void* peb_ptr = nullptr;
|
||||||
|
_asm {
|
||||||
|
PUSH EAX
|
||||||
|
MOV EAX, FS:[0x30]
|
||||||
|
MOV peb_ptr, EAX
|
||||||
|
POP EAX
|
||||||
|
}
|
||||||
|
void* ldr_ptr = *((void**)((unsigned char*)peb_ptr + 0xc));
|
||||||
|
void* cur_ptr = *((void**)((unsigned char*)ldr_ptr + 0x0c));
|
||||||
|
void* next_ptr = cur_ptr;
|
||||||
|
do {
|
||||||
|
void* next = *((void**)((unsigned char*)next_ptr));
|
||||||
|
void* last = *((void**)((unsigned char*)next_ptr + 0x4));
|
||||||
|
void* base_addr = *((void**)((unsigned char*)next_ptr + 0x18));
|
||||||
|
if (base_addr == module) {
|
||||||
|
*((void**)((unsigned char*)last)) = next;
|
||||||
|
*((void**)((unsigned char*)next + 0x4)) = last;
|
||||||
|
cur_ptr = next;
|
||||||
|
}
|
||||||
|
next_ptr = *((void**)next_ptr);
|
||||||
|
} while (cur_ptr != next_ptr);
|
||||||
|
}
|
||||||
|
} // namespace wxhelper
|
48
src/hide_module.h
Normal file
48
src/hide_module.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#ifndef WXHELEPER_HIDE_MODULE_H_
|
||||||
|
#define WXHELEPER_HIDE_MODULE_H_
|
||||||
|
#include <Windows.h>
|
||||||
|
namespace wxhelper {
|
||||||
|
typedef struct _UNICODE_STRING {
|
||||||
|
USHORT Length;
|
||||||
|
USHORT MaximumLength;
|
||||||
|
PWSTR Buffer;
|
||||||
|
} UNICODE_STRING, *PUNICODE_STRING;
|
||||||
|
|
||||||
|
typedef struct _PEB_LDR_DATA {
|
||||||
|
ULONG Length;
|
||||||
|
BOOLEAN Initialized;
|
||||||
|
PVOID SsHandle;
|
||||||
|
LIST_ENTRY InLoadOrderModuleList;
|
||||||
|
LIST_ENTRY InMemoryOrderModuleList;
|
||||||
|
LIST_ENTRY InInitializationOrderModuleList;
|
||||||
|
} PEB_LDR_DATA, *PPEB_LDR_DATA;
|
||||||
|
|
||||||
|
typedef struct _LDR_DATA_TABLE_ENTRY {
|
||||||
|
LIST_ENTRY InLoadOrderModuleList;
|
||||||
|
LIST_ENTRY InMemoryOrderModuleList;
|
||||||
|
LIST_ENTRY InInitializationOrderModuleList;
|
||||||
|
void* BaseAddress;
|
||||||
|
void* EntryPoint;
|
||||||
|
ULONG SizeOfImage;
|
||||||
|
UNICODE_STRING FullDllName;
|
||||||
|
UNICODE_STRING BaseDllName;
|
||||||
|
ULONG Flags;
|
||||||
|
SHORT LoadCount;
|
||||||
|
SHORT TlsIndex;
|
||||||
|
HANDLE SectionHandle;
|
||||||
|
ULONG CheckSum;
|
||||||
|
ULONG TimeDateStamp;
|
||||||
|
} LDR_MODULE, *PLDR_MODULE;
|
||||||
|
|
||||||
|
|
||||||
|
class HideModule {
|
||||||
|
private:
|
||||||
|
/* data */
|
||||||
|
public:
|
||||||
|
static void Hide(const char* module_name);
|
||||||
|
static void Hide(HMODULE module);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace wxhelper
|
||||||
|
#endif
|
533
src/hooks.cc
Normal file
533
src/hooks.cc
Normal file
@ -0,0 +1,533 @@
|
|||||||
|
#include <Ws2tcpip.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include "easylogging++.h"
|
||||||
|
#include "pch.h"
|
||||||
|
#include "wechat_function.h"
|
||||||
|
using namespace nlohmann;
|
||||||
|
using namespace std;
|
||||||
|
namespace wxhelper {
|
||||||
|
namespace hooks {
|
||||||
|
static int server_port_ = 0;
|
||||||
|
static bool msg_hook_flag_ = false;
|
||||||
|
static char server_ip_[16] = "127.0.0.1";
|
||||||
|
|
||||||
|
static char msg_asm_code_[5] = {0};
|
||||||
|
static DWORD msg_back_addr_ = 0;
|
||||||
|
static DWORD msg_next_addr_ = 0;
|
||||||
|
|
||||||
|
static char sns_asm_code_[5] = {0};
|
||||||
|
static DWORD sns_back_addr_ = 0;
|
||||||
|
static DWORD sns_next_addr_ = 0;
|
||||||
|
|
||||||
|
static bool log_hook_flag_ = false;
|
||||||
|
static char log_asm_code_[5] = {0};
|
||||||
|
static DWORD log_back_addr_ = 0;
|
||||||
|
static DWORD log_next_addr_ = 0;
|
||||||
|
|
||||||
|
static bool search_contact_flag_ = false;
|
||||||
|
static char search_contact_asm_code_[5] = {0};
|
||||||
|
static DWORD search_contact_back_addr_ = 0;
|
||||||
|
static DWORD search_contact_next_addr_ = 0;
|
||||||
|
|
||||||
|
static bool error_code_flag_ = false;
|
||||||
|
static char error_code_asm_code_[5] = {0};
|
||||||
|
static DWORD error_code_back_addr_ = 0;
|
||||||
|
static DWORD error_code_next_addr_ = 0;
|
||||||
|
|
||||||
|
bool user_info_flag_ = false;
|
||||||
|
static char user_info_asm_code_[5] = {0};
|
||||||
|
static DWORD user_info_back_addr_ = 0;
|
||||||
|
static DWORD user_info_next_addr_ = 0;
|
||||||
|
|
||||||
|
UserInfo userinfo = {};
|
||||||
|
|
||||||
|
void SendSocketMessage(InnerMessageStruct *msg) {
|
||||||
|
if (msg == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unique_ptr<InnerMessageStruct> sms(msg);
|
||||||
|
json j_msg =
|
||||||
|
json::parse(msg->buffer, msg->buffer + msg->length, nullptr, false);
|
||||||
|
if (j_msg.is_discarded() == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
string jstr = j_msg.dump() + "\n";
|
||||||
|
|
||||||
|
if (server_port_ == 0) {
|
||||||
|
LOG(INFO) << "http server port error :" << server_port_;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (client_socket < 0) {
|
||||||
|
LOG(INFO) << "socket init fail";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BOOL status = false;
|
||||||
|
sockaddr_in client_addr;
|
||||||
|
memset(&client_addr, 0, sizeof(client_addr));
|
||||||
|
client_addr.sin_family = AF_INET;
|
||||||
|
client_addr.sin_port = htons((u_short)server_port_);
|
||||||
|
InetPtonA(AF_INET, server_ip_, &client_addr.sin_addr.s_addr);
|
||||||
|
if (connect(client_socket, reinterpret_cast<sockaddr *>(&client_addr),
|
||||||
|
sizeof(sockaddr)) < 0) {
|
||||||
|
LOG(INFO) << "socket connect fail";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char recv_buf[1024] = {0};
|
||||||
|
int ret = send(client_socket, jstr.c_str(), jstr.size(), 0);
|
||||||
|
if (ret == -1 || ret == 0) {
|
||||||
|
LOG(INFO) << "socket send fail ,ret:" << ret;
|
||||||
|
closesocket(client_socket);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(recv_buf, 0, sizeof(recv_buf));
|
||||||
|
ret = recv(client_socket, recv_buf, sizeof(recv_buf), 0);
|
||||||
|
closesocket(client_socket);
|
||||||
|
if (ret == -1 || ret == 0) {
|
||||||
|
LOG(INFO) << "socket recv fail ,ret:" << ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __cdecl OnRecvMsg(DWORD msg_addr) {
|
||||||
|
json j_msg;
|
||||||
|
unsigned long long msgid = *(unsigned long long *)(msg_addr + 0x30);
|
||||||
|
j_msg["msgId"] = msgid;
|
||||||
|
j_msg["pid"] = GetCurrentProcessId();
|
||||||
|
j_msg["type"] = *(DWORD *)(msg_addr + 0x38);
|
||||||
|
j_msg["isSendMsg"] = *(BOOL *)(msg_addr + 0x3C);
|
||||||
|
if (j_msg["isSendMsg"].get<BOOL>()) {
|
||||||
|
j_msg["isSendByPhone"] = (int)(*(BYTE *)(msg_addr + 0xD8));
|
||||||
|
}
|
||||||
|
j_msg["time"] =
|
||||||
|
Utils::WstringToUTF8(Utils::GetTimeW(*(DWORD *)(msg_addr + 0x44)));
|
||||||
|
j_msg["timestamp"] = *(DWORD *)(msg_addr + 0x44);
|
||||||
|
j_msg["fromGroup"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x48));
|
||||||
|
int length = *(DWORD *)(msg_addr + 0x178);
|
||||||
|
if (length == 0) {
|
||||||
|
j_msg["fromUser"] = j_msg["fromGroup"].get<std::string>();
|
||||||
|
} else {
|
||||||
|
j_msg["fromUser"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x174));
|
||||||
|
}
|
||||||
|
int content_len = *(DWORD *)(msg_addr + 0x74);
|
||||||
|
if (content_len > 0) {
|
||||||
|
j_msg["content"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x70));
|
||||||
|
}
|
||||||
|
int sign_len = *(DWORD *)(msg_addr + 0x18C);
|
||||||
|
if (sign_len > 0) {
|
||||||
|
j_msg["sign"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x188));
|
||||||
|
}
|
||||||
|
int thumb_len = *(DWORD *)(msg_addr + 0x1A0);
|
||||||
|
if (thumb_len > 0) {
|
||||||
|
j_msg["thumbPath"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x19C));
|
||||||
|
}
|
||||||
|
int path_len = *(DWORD *)(msg_addr + 0x1B4);
|
||||||
|
if (path_len > 0) {
|
||||||
|
j_msg["path"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x1B0));
|
||||||
|
}
|
||||||
|
|
||||||
|
int signature_len = *(DWORD *)(msg_addr + 0x1F4);
|
||||||
|
if (signature_len > 0) {
|
||||||
|
j_msg["signature"] = Utils::WstringToUTF8(READ_WSTRING(msg_addr, 0x1F0));
|
||||||
|
}
|
||||||
|
|
||||||
|
string jstr = j_msg.dump() + '\n';
|
||||||
|
InnerMessageStruct *inner_msg = new InnerMessageStruct;
|
||||||
|
inner_msg->buffer = new char[jstr.size() + 1];
|
||||||
|
memcpy(inner_msg->buffer, jstr.c_str(), jstr.size() + 1);
|
||||||
|
inner_msg->length = jstr.size();
|
||||||
|
HANDLE thread = CreateThread(
|
||||||
|
NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessage, inner_msg, NULL, 0);
|
||||||
|
if (thread) {
|
||||||
|
CloseHandle(thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief hook msg implement
|
||||||
|
_declspec(naked) void HandleSyncMsg() {
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
PUSH ECX
|
||||||
|
CALL OnRecvMsg
|
||||||
|
ADD ESP, 0x4
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
CALL msg_next_addr_
|
||||||
|
JMP msg_back_addr_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __cdecl OnSnsTimeLineMsg(DWORD msg_addr) {
|
||||||
|
json j_sns;
|
||||||
|
DWORD begin_addr = *(DWORD *)(msg_addr + 0x20);
|
||||||
|
DWORD end_addr = *(DWORD *)(msg_addr + 0x24);
|
||||||
|
if (begin_addr == 0) {
|
||||||
|
j_sns = {{"data", json::array()}};
|
||||||
|
} else {
|
||||||
|
while (begin_addr < end_addr) {
|
||||||
|
json j_item;
|
||||||
|
j_item["snsId"] = *(unsigned long long *)(begin_addr);
|
||||||
|
j_item["createTime"] = *(DWORD *)(begin_addr + 0x2C);
|
||||||
|
|
||||||
|
j_item["senderId"] = Utils::WstringToUTF8(READ_WSTRING(begin_addr, 0x18));
|
||||||
|
|
||||||
|
j_item["content"] = Utils::WstringToUTF8(READ_WSTRING(begin_addr, 0x3c));
|
||||||
|
|
||||||
|
j_item["xml"] = Utils::WstringToUTF8(READ_WSTRING(begin_addr, 0x384));
|
||||||
|
|
||||||
|
j_sns["data"].push_back(j_item);
|
||||||
|
begin_addr += 0xB48;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string jstr = j_sns.dump() + '\n';
|
||||||
|
InnerMessageStruct *inner_msg = new InnerMessageStruct;
|
||||||
|
inner_msg->buffer = new char[jstr.size() + 1];
|
||||||
|
memcpy(inner_msg->buffer, jstr.c_str(), jstr.size() + 1);
|
||||||
|
inner_msg->length = jstr.size();
|
||||||
|
HANDLE thread = CreateThread(
|
||||||
|
NULL, 0, (LPTHREAD_START_ROUTINE)SendSocketMessage, inner_msg, NULL, 0);
|
||||||
|
if (thread) {
|
||||||
|
CloseHandle(thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief hook sns msg implement
|
||||||
|
_declspec(naked) void HandleSNSMsg() {
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
PUSH [ESP + 0x24]
|
||||||
|
CALL OnSnsTimeLineMsg
|
||||||
|
ADD ESP, 0x4
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
CALL sns_next_addr_
|
||||||
|
JMP sns_back_addr_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int HookRecvMsg(char *client_ip, int port) {
|
||||||
|
server_port_ = port;
|
||||||
|
strcpy_s(server_ip_, client_ip);
|
||||||
|
DWORD base = Utils::GetWeChatWinBase();
|
||||||
|
if (!base) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg_hook_flag_) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD hook_recv_msg_addr = base + WX_RECV_MSG_HOOK_OFFSET;
|
||||||
|
msg_next_addr_ = base + WX_RECV_MSG_HOOK_NEXT_OFFSET;
|
||||||
|
msg_back_addr_ = hook_recv_msg_addr + 0x5;
|
||||||
|
LOG(INFO) << "base" << base;
|
||||||
|
LOG(INFO) << "msg_next_addr_" << msg_next_addr_;
|
||||||
|
LOG(INFO) << "msg_back_addr_" << msg_back_addr_;
|
||||||
|
Utils::HookAnyAddress(hook_recv_msg_addr, (LPVOID)HandleSyncMsg,
|
||||||
|
msg_asm_code_);
|
||||||
|
|
||||||
|
DWORD hook_sns_msg_addr = base + WX_SNS_HOOK_OFFSET;
|
||||||
|
sns_next_addr_ = base + WX_SNS_HOOK_NEXT_OFFSET;
|
||||||
|
sns_back_addr_ = hook_sns_msg_addr + 0x5;
|
||||||
|
LOG(INFO) << "base" << base;
|
||||||
|
LOG(INFO) << "sns_next_addr_" << sns_next_addr_;
|
||||||
|
LOG(INFO) << "sns_back_addr_" << sns_back_addr_;
|
||||||
|
Utils::HookAnyAddress(hook_sns_msg_addr, (LPVOID)HandleSNSMsg, sns_asm_code_);
|
||||||
|
|
||||||
|
msg_hook_flag_ = true;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnHookRecvMsg() {
|
||||||
|
server_port_ = 0;
|
||||||
|
if (!msg_hook_flag_) {
|
||||||
|
LOG(INFO) << "this port already hooked";
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
DWORD base = Utils::GetWeChatWinBase();
|
||||||
|
DWORD hook_recv_msg_addr = base + WX_RECV_MSG_HOOK_OFFSET;
|
||||||
|
DWORD hook_sns_addr = base + WX_SNS_HOOK_OFFSET;
|
||||||
|
Utils::UnHookAnyAddress(hook_recv_msg_addr, msg_asm_code_);
|
||||||
|
Utils::UnHookAnyAddress(hook_sns_addr, sns_asm_code_);
|
||||||
|
msg_hook_flag_ = false;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintLog(DWORD addr) {
|
||||||
|
if (!addr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DWORD dwId = 0;
|
||||||
|
char *msg = (char *)addr;
|
||||||
|
int size = MultiByteToWideChar(CP_UTF8, 0, msg, -1, 0, 0);
|
||||||
|
wchar_t *w_msg = new wchar_t[size + 1];
|
||||||
|
memset(w_msg, 0, (size + 1) * 2);
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, msg, -1, w_msg, size);
|
||||||
|
size = WideCharToMultiByte(CP_ACP, 0, w_msg, -1, 0, 0, 0, 0);
|
||||||
|
char *ansi_message = new char[size + 1];
|
||||||
|
memset(ansi_message, 0, size + 1);
|
||||||
|
WideCharToMultiByte(CP_ACP, 0, w_msg, -1, ansi_message, size, 0, 0);
|
||||||
|
delete[] w_msg;
|
||||||
|
w_msg = NULL;
|
||||||
|
LOG(INFO) << ansi_message;
|
||||||
|
delete[] ansi_message;
|
||||||
|
ansi_message = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_declspec(naked) void HandleLog() {
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
PUSH EAX
|
||||||
|
CALL PrintLog
|
||||||
|
ADD ESP, 0x4
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
CALL log_next_addr_
|
||||||
|
JMP log_back_addr_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int HookLog() {
|
||||||
|
DWORD base = Utils::GetWeChatWinBase();
|
||||||
|
if (!base) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (log_hook_flag_) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
DWORD hook_log_addr = base + WX_HOOK_LOG_OFFSET;
|
||||||
|
log_next_addr_ = base + WX_HOOK_LOG_NEXT_OFFSET;
|
||||||
|
log_back_addr_ = hook_log_addr + 0x5;
|
||||||
|
Utils::HookAnyAddress(hook_log_addr, (LPVOID)HandleLog, log_asm_code_);
|
||||||
|
log_hook_flag_ = true;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int UnHookLog() {
|
||||||
|
if (!log_hook_flag_) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
DWORD base = Utils::GetWeChatWinBase();
|
||||||
|
DWORD hook_log_addr = base + WX_HOOK_LOG_OFFSET;
|
||||||
|
Utils::UnHookAnyAddress(hook_log_addr, log_asm_code_);
|
||||||
|
log_hook_flag_ = FALSE;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetErrorCode(int code) { userinfo.error_code = code; }
|
||||||
|
|
||||||
|
void SetUserInfoDetail(DWORD address) {
|
||||||
|
LOG(INFO) << "hook userinfo addr" <<&userinfo;
|
||||||
|
DWORD length = *(DWORD *)(address + 0x8);
|
||||||
|
userinfo.keyword = new wchar_t[length + 1];
|
||||||
|
userinfo.keyword_len = length;
|
||||||
|
if (length) {
|
||||||
|
memcpy(userinfo.keyword, (wchar_t *)(*(DWORD *)(address + 0x4)),
|
||||||
|
(length + 1) * sizeof(wchar_t));
|
||||||
|
} else {
|
||||||
|
ZeroMemory(userinfo.keyword, (length + 1) * sizeof(wchar_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = *(DWORD *)(address + 0x1C);
|
||||||
|
userinfo.v3 = new wchar_t[length + 1];
|
||||||
|
userinfo.v3_len = length;
|
||||||
|
if (length) {
|
||||||
|
memcpy(userinfo.v3, (wchar_t *)(*(DWORD *)(address + 0x18)),
|
||||||
|
(length + 1) * sizeof(wchar_t));
|
||||||
|
} else {
|
||||||
|
ZeroMemory(userinfo.v3, (length + 1) * sizeof(wchar_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = *(DWORD *)(address + 0x30);
|
||||||
|
userinfo.big_image = new wchar_t[length + 1];
|
||||||
|
userinfo.big_image_len = length;
|
||||||
|
if (length) {
|
||||||
|
memcpy(userinfo.big_image, (wchar_t *)(*(DWORD *)(address + 0x2C)),
|
||||||
|
(length + 1) * sizeof(wchar_t));
|
||||||
|
} else {
|
||||||
|
ZeroMemory(userinfo.big_image, (length + 1) * sizeof(wchar_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = *(DWORD *)(address + 0xC8);
|
||||||
|
userinfo.nickname = new wchar_t[length + 1];
|
||||||
|
userinfo.nickname_len = length;
|
||||||
|
if (length) {
|
||||||
|
memcpy(userinfo.nickname, (wchar_t *)(*(DWORD *)(address + 0xC4)),
|
||||||
|
(length + 1) * sizeof(wchar_t));
|
||||||
|
} else {
|
||||||
|
ZeroMemory(userinfo.nickname, (length + 1) * sizeof(wchar_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = *(DWORD *)(address + 0x108);
|
||||||
|
userinfo.v2 = new wchar_t[length + 1];
|
||||||
|
userinfo.v2_len = length;
|
||||||
|
if (length) {
|
||||||
|
memcpy(userinfo.v2, (wchar_t *)(*(DWORD *)(address + 0x104)),
|
||||||
|
(length + 1) * sizeof(wchar_t));
|
||||||
|
} else {
|
||||||
|
ZeroMemory(userinfo.v2, (length + 1) * sizeof(wchar_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = *(DWORD *)(address + 0x16C);
|
||||||
|
userinfo.small_image = new wchar_t[length + 1];
|
||||||
|
userinfo.small_image_len = length;
|
||||||
|
if (length) {
|
||||||
|
memcpy(userinfo.small_image, (wchar_t *)(*(DWORD *)(address + 0x168)),
|
||||||
|
(length + 1) * sizeof(wchar_t));
|
||||||
|
} else {
|
||||||
|
ZeroMemory(userinfo.small_image, (length + 1) * sizeof(wchar_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = *(DWORD *)(address + 0x1F8);
|
||||||
|
userinfo.signature = new wchar_t[length + 1];
|
||||||
|
userinfo.signature_len = length;
|
||||||
|
if (length) {
|
||||||
|
memcpy(userinfo.signature, (wchar_t *)(*(DWORD *)(address + 0x1F4)),
|
||||||
|
(length + 1) * sizeof(wchar_t));
|
||||||
|
} else {
|
||||||
|
ZeroMemory(userinfo.signature, (length + 1) * sizeof(wchar_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = *(DWORD *)(address + 0x20C);
|
||||||
|
userinfo.nation = new wchar_t[length + 1];
|
||||||
|
userinfo.nation_len = length;
|
||||||
|
if (length) {
|
||||||
|
memcpy(userinfo.nation, (wchar_t *)(*(DWORD *)(address + 0x208)),
|
||||||
|
(length + 1) * sizeof(wchar_t));
|
||||||
|
} else {
|
||||||
|
ZeroMemory(userinfo.nation, (length + 1) * sizeof(wchar_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = *(DWORD *)(address + 0x220);
|
||||||
|
userinfo.province = new wchar_t[length + 1];
|
||||||
|
userinfo.province_len = length;
|
||||||
|
if (length) {
|
||||||
|
memcpy(userinfo.province, (wchar_t *)(*(DWORD *)(address + 0x21C)),
|
||||||
|
(length + 1) * sizeof(wchar_t));
|
||||||
|
} else {
|
||||||
|
ZeroMemory(userinfo.province, (length + 1) * sizeof(wchar_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = *(DWORD *)(address + 0x234);
|
||||||
|
userinfo.city = new wchar_t[length + 1];
|
||||||
|
userinfo.city_len = length;
|
||||||
|
if (length) {
|
||||||
|
memcpy(userinfo.city, (wchar_t *)(*(DWORD *)(address + 0x230)),
|
||||||
|
(length + 1) * sizeof(wchar_t));
|
||||||
|
} else {
|
||||||
|
ZeroMemory(userinfo.city, (length + 1) * sizeof(wchar_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
userinfo.sex = *(DWORD *)(address + 0x1BC);
|
||||||
|
userinfo.over = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteUserInfoCache() {
|
||||||
|
if (userinfo.keyword) {
|
||||||
|
delete userinfo.keyword;
|
||||||
|
}
|
||||||
|
if (userinfo.v2) {
|
||||||
|
delete userinfo.v2;
|
||||||
|
}
|
||||||
|
if (userinfo.v3) {
|
||||||
|
delete userinfo.v3;
|
||||||
|
}
|
||||||
|
if (userinfo.nickname) {
|
||||||
|
delete userinfo.nickname;
|
||||||
|
}
|
||||||
|
if (userinfo.nation) {
|
||||||
|
delete userinfo.nation;
|
||||||
|
}
|
||||||
|
if (userinfo.province) {
|
||||||
|
delete userinfo.province;
|
||||||
|
}
|
||||||
|
if (userinfo.city) {
|
||||||
|
delete userinfo.city;
|
||||||
|
}
|
||||||
|
if (userinfo.signature) {
|
||||||
|
delete userinfo.signature;
|
||||||
|
}
|
||||||
|
if (userinfo.small_image) {
|
||||||
|
delete userinfo.small_image;
|
||||||
|
}
|
||||||
|
if (userinfo.big_image) {
|
||||||
|
delete userinfo.big_image;
|
||||||
|
}
|
||||||
|
ZeroMemory(&userinfo, sizeof(UserInfo));
|
||||||
|
userinfo.error_code = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(naked) void HandleErrorCode() {
|
||||||
|
__asm {
|
||||||
|
PUSHAD;
|
||||||
|
PUSHFD;
|
||||||
|
PUSH ESI;
|
||||||
|
CALL SetErrorCode;
|
||||||
|
ADD ESP, 0x4;
|
||||||
|
POPFD;
|
||||||
|
POPAD;
|
||||||
|
CALL error_code_next_addr_;
|
||||||
|
JMP error_code_back_addr_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(naked) void HandleUserInfoDetail() {
|
||||||
|
__asm {
|
||||||
|
PUSHAD;
|
||||||
|
PUSHFD;
|
||||||
|
PUSH dword ptr [EBP + 0x14];
|
||||||
|
CALL SetUserInfoDetail;
|
||||||
|
ADD ESP, 0x4;
|
||||||
|
POPFD;
|
||||||
|
POPAD;
|
||||||
|
CALL user_info_next_addr_;
|
||||||
|
JMP user_info_back_addr_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int HookSearchContact() {
|
||||||
|
DWORD base = Utils::GetWeChatWinBase();
|
||||||
|
if (!base) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (search_contact_flag_) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
DWORD hook_error_code_addr = base + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET;
|
||||||
|
error_code_next_addr_ = base + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSET;
|
||||||
|
error_code_back_addr_ = hook_error_code_addr + 0x5;
|
||||||
|
Utils::HookAnyAddress(hook_error_code_addr, (LPVOID)HandleErrorCode,
|
||||||
|
error_code_asm_code_);
|
||||||
|
|
||||||
|
DWORD hook_user_info_addr = base + WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET;
|
||||||
|
user_info_next_addr_ = base + WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSET;
|
||||||
|
user_info_back_addr_ = hook_user_info_addr + 0x5;
|
||||||
|
|
||||||
|
Utils::HookAnyAddress(hook_user_info_addr, (LPVOID)HandleUserInfoDetail,
|
||||||
|
user_info_asm_code_);
|
||||||
|
error_code_flag_ = true;
|
||||||
|
user_info_flag_ = true;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UnHookSearchContact() {
|
||||||
|
DWORD base = Utils::GetWeChatWinBase();
|
||||||
|
DWORD hook_user_info_addr = base + WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET;
|
||||||
|
DWORD hook_error_code_addr = base + WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET;
|
||||||
|
|
||||||
|
if (!user_info_flag_) return 2;
|
||||||
|
Utils::UnHookAnyAddress(hook_user_info_addr, user_info_asm_code_);
|
||||||
|
user_info_flag_ = false;
|
||||||
|
|
||||||
|
if (!error_code_flag_) return 2;
|
||||||
|
Utils::UnHookAnyAddress(hook_error_code_addr, error_code_asm_code_);
|
||||||
|
error_code_flag_ = false;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} // namespace hooks
|
||||||
|
} // namespace wxhelper
|
23
src/hooks.h
Normal file
23
src/hooks.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef WXHELPER_HOOKS_H_
|
||||||
|
#define WXHELPER_HOOKS_H_
|
||||||
|
#include "Windows.h"
|
||||||
|
#include "wechat_function.h"
|
||||||
|
namespace wxhelper {
|
||||||
|
namespace hooks {
|
||||||
|
extern UserInfo userinfo;
|
||||||
|
extern bool user_info_flag_ ;
|
||||||
|
|
||||||
|
int HookRecvMsg(char* client_ip, int port);
|
||||||
|
|
||||||
|
int UnHookRecvMsg();
|
||||||
|
|
||||||
|
void SendSocketMessage(InnerMessageStruct* msg);
|
||||||
|
|
||||||
|
int HookLog();
|
||||||
|
int UnHookLog();
|
||||||
|
int HookSearchContact();
|
||||||
|
int UnHookSearchContact();
|
||||||
|
void DeleteUserInfoCache();
|
||||||
|
} // namespace hooks
|
||||||
|
} // namespace wxhelper
|
||||||
|
#endif
|
599
src/http_handler.cc
Normal file
599
src/http_handler.cc
Normal file
@ -0,0 +1,599 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "http_handler.h"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
#include "account_mgr.h"
|
||||||
|
#include "api_route.h"
|
||||||
|
#include "chat_room_mgr.h"
|
||||||
|
#include "contact_mgr.h"
|
||||||
|
#include "db.h"
|
||||||
|
#include "easylogging++.h"
|
||||||
|
#include "hooks.h"
|
||||||
|
#include "misc_mgr.h"
|
||||||
|
#include "send_message_mgr.h"
|
||||||
|
#include "sns_mgr.h"
|
||||||
|
#include "global_context.h"
|
||||||
|
#include "hooks.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace nlohmann;
|
||||||
|
|
||||||
|
namespace wxhelper {
|
||||||
|
string GetParamOfGetReq(mg_http_message *hm, string name) {
|
||||||
|
string ret;
|
||||||
|
char *buffer = new char[hm->query.len + 1];
|
||||||
|
ZeroMemory(buffer, hm->query.len + 1);
|
||||||
|
int len = mg_http_get_var(&hm->query, name.c_str(), buffer, hm->query.len);
|
||||||
|
if (len > 0) ret = string(buffer, len);
|
||||||
|
delete[] buffer;
|
||||||
|
buffer = NULL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetIntParam(json data, string key) {
|
||||||
|
int result;
|
||||||
|
try {
|
||||||
|
result = data[key].get<int>();
|
||||||
|
} catch (json::exception) {
|
||||||
|
result = STRING2INT(data[key].get<string>());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
wstring GetWStringParam(json data, string key) {
|
||||||
|
return Utils::UTF8ToWstring(data[key].get<string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long GetULong64Param(json j_data, string key) {
|
||||||
|
unsigned long long result = 0;
|
||||||
|
try {
|
||||||
|
result = j_data[key].get<ULONG64>();
|
||||||
|
} catch (json::exception) {
|
||||||
|
string value = j_data[key].get<string>();
|
||||||
|
istringstream is(value);
|
||||||
|
is >> result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static vector<wstring> getArrayParam(json j_data, string key) {
|
||||||
|
vector<wstring> result;
|
||||||
|
wstring param = GetWStringParam(j_data, key);
|
||||||
|
result = Utils::split(param, L',');
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
string Dispatch(struct mg_connection *c, struct mg_http_message *hm) {
|
||||||
|
int is_post = 0;
|
||||||
|
string ret;
|
||||||
|
if (mg_vcasecmp(&hm->method, "POST") == 0) {
|
||||||
|
is_post = 1;
|
||||||
|
}
|
||||||
|
el::Logger *defaultLogger = el::Loggers::getLogger("default");
|
||||||
|
defaultLogger->info("method: %v body: %v", hm->method.ptr, hm->body.ptr);
|
||||||
|
LOG_IF(is_post != 1, INFO) << "request method is not post";
|
||||||
|
|
||||||
|
if (is_post == 0) {
|
||||||
|
json ret_data = {{"result", "ERROR"}, {"msg", "not support method"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
json j_param =
|
||||||
|
json::parse(hm->body.ptr, hm->body.ptr + hm->body.len, nullptr, false);
|
||||||
|
if (hm->body.len != 0 && j_param.is_discarded() == true) {
|
||||||
|
json ret_data = {{"result", "ERROR"}, {"msg", "json string is invalid."}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int api_number = STRING2INT(GetParamOfGetReq(hm, "type"));
|
||||||
|
GlobalContext& g_context = GlobalContext::GetInstance();
|
||||||
|
switch (api_number) {
|
||||||
|
case WECHAT_IS_LOGIN: {
|
||||||
|
int success = -1;
|
||||||
|
success = g_context.account_mgr->CheckLogin();
|
||||||
|
json ret_data = {{"result", "OK"}, {"code", success}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_GET_SELF_INFO: {
|
||||||
|
SelfInfoInner self_info;
|
||||||
|
int success = g_context.account_mgr->GetSelfInfo(self_info);
|
||||||
|
json ret_data = {{"result", "OK"}, {"code", success}};
|
||||||
|
if (success) {
|
||||||
|
json j_info = {
|
||||||
|
{"name", self_info.name},
|
||||||
|
{"city", self_info.city},
|
||||||
|
{"province", self_info.province},
|
||||||
|
{"country", self_info.country},
|
||||||
|
{"account", self_info.account},
|
||||||
|
{"wxid", self_info.wxid},
|
||||||
|
{"mobile", self_info.mobile},
|
||||||
|
{"headImage", self_info.head_img},
|
||||||
|
{"signature", self_info.signature},
|
||||||
|
{"dataSavePath", self_info.data_save_path},
|
||||||
|
{"currentDataPath", self_info.current_data_path},
|
||||||
|
{"dbKey", self_info.db_key},
|
||||||
|
};
|
||||||
|
ret_data["data"] = j_info;
|
||||||
|
}
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_SEND_TEXT: {
|
||||||
|
wstring wxid = GetWStringParam(j_param, "wxid");
|
||||||
|
wstring msg = GetWStringParam(j_param, "msg");
|
||||||
|
int success = g_context.send_mgr->SendText(WS2LPWS(wxid), WS2LPWS(msg));
|
||||||
|
json ret_data = {{"result", "OK"}, {"code", success}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_SEND_AT: {
|
||||||
|
break;
|
||||||
|
wstring chat_room_id = GetWStringParam(j_param, "chatRoomId");
|
||||||
|
vector<wstring> wxids = getArrayParam(j_param, "wxids");
|
||||||
|
wstring msg = GetWStringParam(j_param, "msg");
|
||||||
|
vector<wchar_t *> wxid_list;
|
||||||
|
for (unsigned int i = 0; i < wxids.size(); i++) {
|
||||||
|
wxid_list.push_back(WS2LPWS(wxids[i]));
|
||||||
|
}
|
||||||
|
int success = g_context.send_mgr->SendAtText(WS2LPWS(chat_room_id), wxid_list.data(),
|
||||||
|
wxid_list.size(), WS2LPWS(msg));
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_SEND_CARD: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_SEND_IMAGE: {
|
||||||
|
wstring receiver = GetWStringParam(j_param, "wxid");
|
||||||
|
wstring img_path = GetWStringParam(j_param, "imagePath");
|
||||||
|
int success =
|
||||||
|
g_context.send_mgr->SendImage(WS2LPWS(receiver), WS2LPWS(img_path));
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_SEND_FILE: {
|
||||||
|
wstring receiver = GetWStringParam(j_param, "wxid");
|
||||||
|
wstring file_path = GetWStringParam(j_param, "filePath");
|
||||||
|
int success =
|
||||||
|
g_context.send_mgr->SendFile(WS2LPWS(receiver), WS2LPWS(file_path));
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_SEND_ARTICLE: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_SEND_APP: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_START_HOOK: {
|
||||||
|
int port = GetIntParam(j_param, "port");
|
||||||
|
wstring ip = GetWStringParam(j_param, "ip");
|
||||||
|
string client_ip = Utils::WstringToUTF8(ip);
|
||||||
|
char ip_cstr[16];
|
||||||
|
strcpy_s(ip_cstr, client_ip.c_str());
|
||||||
|
int success = hooks::HookRecvMsg(ip_cstr, port);
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_STOP_HOOK: {
|
||||||
|
int success = hooks::UnHookRecvMsg();
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_START_IMAGE_HOOK: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_STOP_IMAGE_HOOK: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_START_VOICE_HOOK: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_STOP_VOICE_HOOK: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CONTACT_GET_LIST: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CONTACT_CHECK_STATUS: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CONTACT_DEL: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CONTACT_SEARCH_BY_CACHE: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CONTACT_SEARCH_BY_NET: {
|
||||||
|
wstring keyword = GetWStringParam(j_param, "keyword");
|
||||||
|
UserInfo *user = nullptr;
|
||||||
|
int success = g_context.misc_mgr->SearchContactNetScene(WS2LPWS(keyword), &user);
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
if (user) {
|
||||||
|
json info = {
|
||||||
|
{"bigImage", Utils::WCharToUTF8(user->big_image)},
|
||||||
|
{"smallImage", Utils::WCharToUTF8(user->small_image)},
|
||||||
|
{"city", Utils::WCharToUTF8(user->city)},
|
||||||
|
{"nation", Utils::WCharToUTF8(user->nation)},
|
||||||
|
{"nickname", Utils::WCharToUTF8(user->nickname)},
|
||||||
|
{"province", Utils::WCharToUTF8(user->province)},
|
||||||
|
{"sex", user->sex},
|
||||||
|
{"signature", Utils::WCharToUTF8(user->signature)},
|
||||||
|
{"v2", Utils::WCharToUTF8(user->v2)},
|
||||||
|
{"v3", Utils::WCharToUTF8(user->v3)},
|
||||||
|
};
|
||||||
|
ret_data["userInfo"] = info;
|
||||||
|
}
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CONTACT_ADD_BY_WXID: {
|
||||||
|
wstring user_id = GetWStringParam(j_param, "wxid");
|
||||||
|
wstring msg = GetWStringParam(j_param, "msg");
|
||||||
|
int success = g_context.contact_mgr->AddFriendByWxid(WS2LPWS(user_id),WS2LPWS(msg));
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CONTACT_ADD_BY_V3: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CONTACT_ADD_BY_PUBLIC_ID: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CONTACT_VERIFY_APPLY: {
|
||||||
|
wstring v3 = GetWStringParam(j_param, "v3");
|
||||||
|
wstring v4 = GetWStringParam(j_param, "v4");
|
||||||
|
int success = g_context.contact_mgr->VerifyApply(WS2LPWS(v3),WS2LPWS(v4));
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CONTACT_EDIT_REMARK: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CHATROOM_GET_MEMBER_LIST: {
|
||||||
|
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||||
|
ChatRoomInner out{0};
|
||||||
|
int success = g_context.chat_room_mgr->GetMemberFromChatRoom(WS2LPWS(room_id), out);
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
if (success) {
|
||||||
|
json member_info = {
|
||||||
|
{"admin", Utils::WstringToUTF8(out.admin)},
|
||||||
|
{"chatRoomId", Utils::WstringToUTF8(out.chat_room)},
|
||||||
|
{"members", out.members},
|
||||||
|
};
|
||||||
|
ret_data["data"] = member_info;
|
||||||
|
}
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CHATROOM_GET_MEMBER_NICKNAME: {
|
||||||
|
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||||
|
wstring member_id = GetWStringParam(j_param, "memberId");
|
||||||
|
|
||||||
|
wstring nickname =g_context.chat_room_mgr->GetChatRoomMemberNickname(
|
||||||
|
WS2LPWS(room_id), WS2LPWS(member_id));
|
||||||
|
json ret_data = {{"code", 1},
|
||||||
|
{"result", "OK"},
|
||||||
|
{"nickname", Utils::WstringToUTF8(nickname)}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CHATROOM_DEL_MEMBER: {
|
||||||
|
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||||
|
vector<wstring> wxids = getArrayParam(j_param, "memberIds");
|
||||||
|
vector<wchar_t *> wxid_list;
|
||||||
|
for (unsigned int i = 0; i < wxids.size(); i++) {
|
||||||
|
wxid_list.push_back(WS2LPWS(wxids[i]));
|
||||||
|
}
|
||||||
|
int success = g_context.chat_room_mgr->DelMemberFromChatRoom(
|
||||||
|
WS2LPWS(room_id), wxid_list.data(), wxid_list.size());
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CHATROOM_ADD_MEMBER: {
|
||||||
|
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||||
|
vector<wstring> wxids = getArrayParam(j_param, "memberIds");
|
||||||
|
vector<wchar_t *> wxid_list;
|
||||||
|
for (unsigned int i = 0; i < wxids.size(); i++) {
|
||||||
|
wxid_list.push_back(WS2LPWS(wxids[i]));
|
||||||
|
}
|
||||||
|
int success = g_context.chat_room_mgr->AddMemberToChatRoom(
|
||||||
|
WS2LPWS(room_id), wxid_list.data(), wxid_list.size());
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CHATROOM_SET_ANNOUNCEMENT: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CHATROOM_SET_CHATROOM_NAME: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CHATROOM_SET_SELF_NICKNAME: {
|
||||||
|
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||||
|
wstring wxid = GetWStringParam(j_param, "wxid");
|
||||||
|
wstring nick = GetWStringParam(j_param, "nickName");
|
||||||
|
int success = g_context.chat_room_mgr->ModChatRoomMemberNickName(
|
||||||
|
WS2LPWS(room_id), WS2LPWS(wxid), WS2LPWS(nick));
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_DATABASE_GET_HANDLES: {
|
||||||
|
vector<void *> v_ptr = DB::GetInstance().GetDbHandles();
|
||||||
|
json ret_data = {{"data", json::array()}, {"result", "OK"}};
|
||||||
|
for (unsigned int i = 0; i < v_ptr.size(); i++) {
|
||||||
|
json db_info;
|
||||||
|
db_info["tables"] = json::array();
|
||||||
|
DatabaseInfo *db = reinterpret_cast<DatabaseInfo *>(v_ptr[i]);
|
||||||
|
db_info["handle"] = db->handle;
|
||||||
|
wstring dbname(db->db_name);
|
||||||
|
db_info["databaseName"] = Utils::WstringToUTF8(dbname);
|
||||||
|
for (auto table : db->tables) {
|
||||||
|
json table_info = {{"name", table.name},
|
||||||
|
{"tableName", table.table_name},
|
||||||
|
{"sql", table.sql},
|
||||||
|
{"rootpage", table.rootpage}};
|
||||||
|
db_info["tables"].push_back(table_info);
|
||||||
|
}
|
||||||
|
ret_data["data"].push_back(db_info);
|
||||||
|
}
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_DATABASE_BACKUP: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_DATABASE_QUERY: {
|
||||||
|
DWORD db_handle = GetIntParam(j_param, "dbHandle");
|
||||||
|
wstring sql = GetWStringParam(j_param, "sql");
|
||||||
|
string sql_str = Utils::WstringToUTF8(sql);
|
||||||
|
vector<vector<string>> items;
|
||||||
|
int success = DB::GetInstance().Select(db_handle, sql_str.c_str(), items);
|
||||||
|
json ret_data = {
|
||||||
|
{"data", json::array()}, {"code", success}, {"result", "OK"}};
|
||||||
|
if (success == 0) {
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (auto it : items) {
|
||||||
|
json temp_arr = json::array();
|
||||||
|
for (size_t i = 0; i < it.size(); i++) {
|
||||||
|
temp_arr.push_back(it[i]);
|
||||||
|
}
|
||||||
|
ret_data["data"].push_back(temp_arr);
|
||||||
|
}
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_SET_VERSION: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_LOG_START_HOOK: {
|
||||||
|
int success = hooks::HookLog();
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_LOG_STOP_HOOK: {
|
||||||
|
int success = hooks::UnHookLog();
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_BROWSER_OPEN_WITH_URL: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_GET_PUBLIC_MSG: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_FORWARD_MESSAGE: {
|
||||||
|
wstring wxid = GetWStringParam(j_param, "wxid");
|
||||||
|
ULONG64 msgid = GetULong64Param(j_param, "msgid");
|
||||||
|
int success =g_context.send_mgr->ForwardMsg(WS2LPWS(wxid), msgid);
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_GET_QRCODE_IMAGE: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_GET_A8KEY: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_MSG_SEND_XML: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_LOGOUT: {
|
||||||
|
int success = g_context.account_mgr->Logout();
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_GET_TRANSFER: {
|
||||||
|
wstring wxid = GetWStringParam(j_param, "wxid");
|
||||||
|
wstring transcationid = GetWStringParam(j_param, "transcationId");
|
||||||
|
wstring transferid = GetWStringParam(j_param, "transferId");
|
||||||
|
BOOL response =g_context.misc_mgr->DoConfirmReceipt(
|
||||||
|
WS2LPWS(wxid), WS2LPWS(transcationid), WS2LPWS(transferid));
|
||||||
|
json ret_data = {{"msg", response}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_GET_CONTACT_ALL: {
|
||||||
|
vector<Contact> vec;
|
||||||
|
int success = g_context.contact_mgr->GetAllContact(vec);
|
||||||
|
json ret_data = {
|
||||||
|
{"data", json::array()}, {"code", success}, {"result", "OK"}};
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < vec.size(); i++) {
|
||||||
|
json item = {
|
||||||
|
{"customAccount",
|
||||||
|
vec[i].custom_account.length > 0
|
||||||
|
? vec[i].custom_account.ptr != nullptr
|
||||||
|
? Utils::WCharToUTF8(vec[i].custom_account.ptr)
|
||||||
|
: string()
|
||||||
|
: string()},
|
||||||
|
{"delFlag", vec[i].del_flag},
|
||||||
|
{"userName", vec[i].encrypt_name.length > 0
|
||||||
|
? vec[i].encrypt_name.ptr != nullptr
|
||||||
|
? Utils::WCharToUTF8(vec[i].encrypt_name.ptr)
|
||||||
|
: string()
|
||||||
|
: string()},
|
||||||
|
{"type", vec[i].type},
|
||||||
|
{"verifyFlag", vec[i].verify_flag},
|
||||||
|
{"verifyFlag", vec[i].verify_flag},
|
||||||
|
{"wxid", vec[i].wxid.length > 0
|
||||||
|
? Utils::WCharToUTF8(vec[i].wxid.ptr)
|
||||||
|
: string()},
|
||||||
|
};
|
||||||
|
ret_data["data"].push_back(item);
|
||||||
|
}
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_GET_CHATROOM_INFO: {
|
||||||
|
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||||
|
ChatRoomInfoInner chat_room_detail{0};
|
||||||
|
int success = g_context.chat_room_mgr->GetChatRoomDetailInfo(WS2LPWS(room_id),
|
||||||
|
chat_room_detail);
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
if (!success) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
json detail = {
|
||||||
|
{"chatRoomId",
|
||||||
|
chat_room_detail.chat_room_id.length > 0
|
||||||
|
? Utils::WCharToUTF8(chat_room_detail.chat_room_id.ptr)
|
||||||
|
: string()},
|
||||||
|
{"notice", chat_room_detail.notice.length > 0
|
||||||
|
? Utils::WCharToUTF8(chat_room_detail.notice.ptr)
|
||||||
|
: string()},
|
||||||
|
{"admin", chat_room_detail.admin.length > 0
|
||||||
|
? Utils::WCharToUTF8(chat_room_detail.admin.ptr)
|
||||||
|
: string()},
|
||||||
|
{"xml", chat_room_detail.xml.length > 0
|
||||||
|
? Utils::WCharToUTF8(chat_room_detail.xml.ptr)
|
||||||
|
: string()},
|
||||||
|
};
|
||||||
|
ret_data["data"] = detail;
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_GET_IMG_BY_NAME: {
|
||||||
|
wstring image_path = GetWStringParam( j_param, "imagePath");
|
||||||
|
wstring save_path = GetWStringParam( j_param, "savePath");
|
||||||
|
int success =
|
||||||
|
g_context.misc_mgr->GetImgByName(WS2LPWS(image_path),WS2LPWS(save_path)); json
|
||||||
|
ret_data = {{"code", success}, {"result", "OK"}}; ret =
|
||||||
|
ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_DO_OCR: {
|
||||||
|
// wstring image_path = GetWStringParam(j_param, "imagePath");
|
||||||
|
// string text("");
|
||||||
|
// int success = g_context.misc_mgr->DoOCRTask(WS2LPWS(image_path), text);
|
||||||
|
// json ret_data = {{"code", success}, {"result", "OK"}, {"text", text}};
|
||||||
|
// ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_SEND_PAT_MSG: {
|
||||||
|
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||||
|
wstring wxid = GetWStringParam(j_param, "wxid");
|
||||||
|
int success = g_context.misc_mgr->SendPatMsg(WS2LPWS(room_id), WS2LPWS(wxid));
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_SET_TOP_MSG: {
|
||||||
|
wstring wxid = GetWStringParam(j_param, "wxid");
|
||||||
|
ULONG64 msgid = GetULong64Param(j_param, "msgid");
|
||||||
|
int success = g_context.chat_room_mgr->SetTopMsg(WS2LPWS(wxid), msgid);
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_REMOVE_TOP_MSG: {
|
||||||
|
wstring room_id = GetWStringParam(j_param, "chatRoomId");
|
||||||
|
ULONG64 msgid = GetULong64Param(j_param, "msgid");
|
||||||
|
int success = g_context.chat_room_mgr->RemoveTopMsg(WS2LPWS(room_id), msgid);
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_SNS_GET_FIRST_PAGE: {
|
||||||
|
int success = g_context.sns_mgr->GetFirstPage();
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_SNS_GET_NEXT_PAGE: {
|
||||||
|
ULONG64 snsid = GetULong64Param(j_param, "snsId");
|
||||||
|
int success = g_context.sns_mgr->GetNextPage(snsid);
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_CONTACT_NAME: {
|
||||||
|
wstring pri_id = GetWStringParam(j_param, "id");
|
||||||
|
wstring name = g_context.contact_mgr->GetContactOrChatRoomNickname(WS2LPWS(pri_id));
|
||||||
|
json ret_data = {
|
||||||
|
{"code", 1}, {"result", "OK"}, {"name", Utils::WstringToUTF8(name)}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_ATTACH_DOWNLOAD: {
|
||||||
|
ULONG64 msg_id = GetULong64Param(j_param, "msgId");
|
||||||
|
int success = g_context.misc_mgr->DoDownloadTask(msg_id);
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WECHAT_GET_VOICE: {
|
||||||
|
ULONG64 msg_id = GetULong64Param(j_param, "msgId");
|
||||||
|
wstring voice_dir = GetWStringParam(j_param, "voiceDir");
|
||||||
|
int success = g_context.misc_mgr->GetVoice(msg_id, WS2LPWS(voice_dir));
|
||||||
|
json ret_data = {{"code", success}, {"result", "OK"}};
|
||||||
|
ret = ret_data.dump();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpHandler::HttpHandler() {}
|
||||||
|
HttpHandler::~HttpHandler() {}
|
||||||
|
void HttpHandler::HandlerRequest(struct mg_connection *c, void *ev_data) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
|
||||||
|
string ret = R"({"result":"OK"})";
|
||||||
|
if (mg_http_match_uri(hm, "/api/")) {
|
||||||
|
try {
|
||||||
|
ret = Dispatch(c, hm);
|
||||||
|
} catch (json::exception &e) {
|
||||||
|
json res = {{"result", "ERROR"}, {"msg", e.what()}};
|
||||||
|
ret = res.dump();
|
||||||
|
}
|
||||||
|
if (ret != "") {
|
||||||
|
mg_http_reply(c, 200, "", ret.c_str(), 0, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mg_http_reply(c, 500, NULL, "%s", "Invalid URI");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wxhelper
|
17
src/http_handler.h
Normal file
17
src/http_handler.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef WXHELPER_HTTP_HANDLER_H_
|
||||||
|
#define WXHELPER_HTTP_HANDLER_H_
|
||||||
|
#include "handler.h"
|
||||||
|
#include "mongoose.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
namespace wxhelper {
|
||||||
|
class HttpHandler : public Handler {
|
||||||
|
public:
|
||||||
|
HttpHandler();
|
||||||
|
~HttpHandler();
|
||||||
|
void HandlerRequest(struct mg_connection *c, void *ev_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace wxhelper
|
||||||
|
#endif
|
100
src/http_server.cc
Normal file
100
src/http_server.cc
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "http_server.h"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include "api_route.h"
|
||||||
|
|
||||||
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
|
using namespace std;
|
||||||
|
using namespace nlohmann;
|
||||||
|
|
||||||
|
namespace wxhelper {
|
||||||
|
HttpServer& HttpServer::GetInstance() {
|
||||||
|
static HttpServer p;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpServer::Init(int port) {
|
||||||
|
port_ = port;
|
||||||
|
running_ = false;
|
||||||
|
http_handler_ = new HttpHandler();
|
||||||
|
mg_mgr_init(&mgr_);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpServer::~HttpServer() {
|
||||||
|
mg_mgr_free(&mgr_);
|
||||||
|
delete http_handler_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HttpServer::HttpStart() {
|
||||||
|
if (running_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#ifdef _DEBUG
|
||||||
|
Utils::CreateConsole();
|
||||||
|
#endif
|
||||||
|
running_ = true;
|
||||||
|
thread_ = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)StartHttpServer, NULL,
|
||||||
|
NULL, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpServer::StartHttpServer() {
|
||||||
|
string lsten_addr = "http://0.0.0.0:" + to_string(GetInstance().port_);
|
||||||
|
mg_http_listen(&GetInstance().mgr_, lsten_addr.c_str(), EventHandler,
|
||||||
|
&GetInstance().mgr_);
|
||||||
|
for (;;) mg_mgr_poll(&GetInstance().mgr_, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpServer::EventHandler(struct mg_connection *c,
|
||||||
|
int ev, void *ev_data, void *fn_data) {
|
||||||
|
if (ev == MG_EV_OPEN) {
|
||||||
|
// c->is_hexdumping = 1;
|
||||||
|
} else if (ev == MG_EV_HTTP_MSG) {
|
||||||
|
struct mg_http_message *hm = (struct mg_http_message *)ev_data;
|
||||||
|
if (mg_http_match_uri(hm, "/websocket")) {
|
||||||
|
mg_ws_upgrade(c, hm, NULL);
|
||||||
|
} else if (mg_http_match_uri(hm, "/api/")) {
|
||||||
|
GetInstance().HandleHttpRequest(c,hm);
|
||||||
|
} else {
|
||||||
|
mg_http_reply(c, 500, NULL, "%s", "Invalid URI");
|
||||||
|
}
|
||||||
|
} else if (ev == MG_EV_WS_MSG) {
|
||||||
|
|
||||||
|
GetInstance().HandleWebsocketRequest(c,ev_data);
|
||||||
|
}
|
||||||
|
(void)fn_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpServer::HandleHttpRequest(struct mg_connection *c,
|
||||||
|
void *ev_data) {
|
||||||
|
|
||||||
|
http_handler_->HandlerRequest(c,ev_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpServer::HandleWebsocketRequest(struct mg_connection *c,
|
||||||
|
void *ev_data) {
|
||||||
|
// Got websocket frame. Received data is wm->data. Echo it back!
|
||||||
|
struct mg_ws_message *wm = (struct mg_ws_message *)ev_data;
|
||||||
|
mg_ws_send(c, wm->data.ptr, wm->data.len, WEBSOCKET_OP_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HttpServer::HttpClose() {
|
||||||
|
if (!running_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#ifdef _DEBUG
|
||||||
|
Utils::CloseConsole();
|
||||||
|
#endif
|
||||||
|
running_ = false;
|
||||||
|
if (thread_) {
|
||||||
|
WaitForSingleObject(thread_, -1);
|
||||||
|
CloseHandle(thread_);
|
||||||
|
thread_ = NULL;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wxhelper
|
35
src/http_server.h
Normal file
35
src/http_server.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef WXHELPER_HTTP_SERVER_H_
|
||||||
|
#define WXHELPER_HTTP_SERVER_H_
|
||||||
|
|
||||||
|
#include <mongoose.h>
|
||||||
|
|
||||||
|
#include "http_handler.h"
|
||||||
|
namespace wxhelper {
|
||||||
|
class HttpServer {
|
||||||
|
public:
|
||||||
|
static HttpServer &GetInstance();
|
||||||
|
bool HttpStart();
|
||||||
|
bool HttpClose();
|
||||||
|
void Init(int port);
|
||||||
|
|
||||||
|
private:
|
||||||
|
HttpServer(){};
|
||||||
|
HttpServer(const HttpServer &) = delete;
|
||||||
|
HttpServer &operator=(const HttpServer &) = delete;
|
||||||
|
~HttpServer();
|
||||||
|
static void StartHttpServer();
|
||||||
|
static void EventHandler(struct mg_connection *c, int ev, void *ev_data,
|
||||||
|
void *fn_data);
|
||||||
|
void HandleHttpRequest(struct mg_connection *c, void *ev_data);
|
||||||
|
void HandleWebsocketRequest(struct mg_connection *c, void *ev_data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int port_;
|
||||||
|
bool running_;
|
||||||
|
struct mg_mgr mgr_;
|
||||||
|
HttpHandler *http_handler_;
|
||||||
|
HANDLE thread_;
|
||||||
|
};
|
||||||
|
} // namespace wxhelper
|
||||||
|
|
||||||
|
#endif
|
37
src/log.cc
Normal file
37
src/log.cc
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include "easylogging++.h"
|
||||||
|
INITIALIZE_EASYLOGGINGPP
|
||||||
|
namespace wxhelper {
|
||||||
|
Log::Log(/* args */) {}
|
||||||
|
|
||||||
|
Log::~Log() {}
|
||||||
|
|
||||||
|
void Log::initialize() {
|
||||||
|
|
||||||
|
el::Configurations conf;
|
||||||
|
// 启用日志
|
||||||
|
conf.setGlobally(el::ConfigurationType::Enabled, "true");
|
||||||
|
// 设置日志文件目录以及文件名
|
||||||
|
conf.setGlobally(el::ConfigurationType::Filename,
|
||||||
|
"log\\log_%datetime{%Y%M%d %H%m%s}.log");
|
||||||
|
// 设置日志文件最大文件大小
|
||||||
|
conf.setGlobally(el::ConfigurationType::MaxLogFileSize, "20971520");
|
||||||
|
// 是否写入文件
|
||||||
|
conf.setGlobally(el::ConfigurationType::ToFile, "true");
|
||||||
|
// 是否输出控制台
|
||||||
|
conf.setGlobally(el::ConfigurationType::ToStandardOutput, "true");
|
||||||
|
// 设置日志输出格式
|
||||||
|
conf.setGlobally(el::ConfigurationType::Format,
|
||||||
|
"[%datetime] [%thread] [%loc] [%level] : %msg");
|
||||||
|
// 设置日志文件写入周期,如下每100条刷新到输出流中
|
||||||
|
#ifdef _DEBUG
|
||||||
|
conf.setGlobally(el::ConfigurationType::LogFlushThreshold, "1");
|
||||||
|
#else
|
||||||
|
conf.setGlobally(el::ConfigurationType::LogFlushThreshold, "100");
|
||||||
|
#endif
|
||||||
|
// 设置配置文件
|
||||||
|
el::Loggers::reconfigureAllLoggers(conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wxhelper
|
18
src/log.h
Normal file
18
src/log.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef WXHELPER_LOG_H_
|
||||||
|
#define WXHELPER_LOG_H_
|
||||||
|
namespace wxhelper{
|
||||||
|
class Log
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/* data */
|
||||||
|
public:
|
||||||
|
Log(/* args */);
|
||||||
|
~Log();
|
||||||
|
void initialize();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
436
src/misc_mgr.cc
Normal file
436
src/misc_mgr.cc
Normal file
@ -0,0 +1,436 @@
|
|||||||
|
#include "misc_mgr.h"
|
||||||
|
|
||||||
|
#include "pch.h"
|
||||||
|
#include "wechat_function.h"
|
||||||
|
#include "base64.h"
|
||||||
|
#include "db.h"
|
||||||
|
#include "hooks.h"
|
||||||
|
#include "easylogging++.h"
|
||||||
|
#define BUFSIZE 1024
|
||||||
|
|
||||||
|
#define JPEG0 0xFF
|
||||||
|
#define JPEG1 0xD8
|
||||||
|
#define JPEG2 0xFF
|
||||||
|
#define PNG0 0x89
|
||||||
|
#define PNG1 0x50
|
||||||
|
#define PNG2 0x4E
|
||||||
|
#define BMP0 0x42
|
||||||
|
#define BMP1 0x4D
|
||||||
|
#define GIF0 0x47
|
||||||
|
#define GIF1 0x49
|
||||||
|
#define GIF2 0x46
|
||||||
|
using namespace std;
|
||||||
|
namespace wxhelper {
|
||||||
|
MiscMgr::MiscMgr(DWORD base) : BaseMgr::BaseMgr(base) {}
|
||||||
|
MiscMgr::~MiscMgr() {}
|
||||||
|
int MiscMgr::SendPatMsg(wchar_t *chat_room_id, wchar_t *wxid) {
|
||||||
|
int success = -1;
|
||||||
|
WeChatString chat_room(chat_room_id);
|
||||||
|
WeChatString self_wxid(wxid);
|
||||||
|
DWORD get_pat_mgr_addr = base_addr_ + WX_PAT_MGR_OFFSET;
|
||||||
|
DWORD send_pat_msg_addr = base_addr_ + WX_SEND_PAT_MSG_OFFSET;
|
||||||
|
DWORD ret_addr = base_addr_ + WX_RET_OFFSET;
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
CALL get_pat_mgr_addr
|
||||||
|
PUSH ret_addr
|
||||||
|
PUSH 0x0
|
||||||
|
PUSH EAX
|
||||||
|
LEA ECX,chat_room
|
||||||
|
LEA EDX,self_wxid
|
||||||
|
CALL send_pat_msg_addr
|
||||||
|
ADD ESP,0xc
|
||||||
|
MOVZX EAX,AL
|
||||||
|
MOV success,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MiscMgr::DoOCRTask(wchar_t *img_path, std::string &result) {
|
||||||
|
int success = -1;
|
||||||
|
WeChatString path(img_path);
|
||||||
|
WeChatString null_obj = {0};
|
||||||
|
WeChatString ocr_result = {0};
|
||||||
|
DWORD ocr_manager_addr = base_addr_ + WX_OCR_MANAGER_OFFSET;
|
||||||
|
DWORD do_ocr_task_addr = base_addr_ + WX_DO_OCR_TASK_OFFSET;
|
||||||
|
DWORD init_addr = base_addr_ + WX_INIT_OBJ_OFFSET;
|
||||||
|
DWORD flag = 0;
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
LEA ECX,ocr_result
|
||||||
|
CALL init_addr
|
||||||
|
CALL ocr_manager_addr
|
||||||
|
LEA ECX,null_obj
|
||||||
|
PUSH ECX
|
||||||
|
LEA ECX,flag
|
||||||
|
PUSH ECX
|
||||||
|
LEA ECX,ocr_result
|
||||||
|
PUSH ECX
|
||||||
|
PUSH 0x0
|
||||||
|
LEA ECX,path
|
||||||
|
PUSH ECX
|
||||||
|
MOV ECX,EAX
|
||||||
|
CALL do_ocr_task_addr
|
||||||
|
MOV success,EAX
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success == 0) {
|
||||||
|
DWORD addr = (DWORD)&ocr_result;
|
||||||
|
DWORD ptr = *(DWORD *)addr;
|
||||||
|
DWORD num = *(DWORD *)(addr + 0x4);
|
||||||
|
if (num <= 0) {
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD header = *(DWORD *)ptr;
|
||||||
|
for (unsigned int i = 0; i < num - 1; i++) {
|
||||||
|
DWORD content = *(DWORD *)header;
|
||||||
|
result += Utils::WstringToUTF8(READ_WSTRING(content, 0x14));
|
||||||
|
|
||||||
|
header = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MiscMgr::DoConfirmReceipt(wchar_t *wxid, wchar_t *transcationid,
|
||||||
|
wchar_t *transferid) {
|
||||||
|
int success = -1;
|
||||||
|
WeChatString recv_id(wxid);
|
||||||
|
WeChatString transcation_id(transcationid);
|
||||||
|
WeChatString transfer_id(transferid);
|
||||||
|
char pay_info[0x134] = {0};
|
||||||
|
DWORD new_pay_info_addr = base_addr_ + WX_NEW_WCPAYINFO_OFFSET;
|
||||||
|
DWORD free_pay_info_addr = base_addr_ + WX_FREE_WCPAYINFO_OFFSET;
|
||||||
|
DWORD do_confirm_addr = base_addr_ + WX_CONFIRM_RECEIPT_OFFSET;
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
LEA ECX,pay_info
|
||||||
|
CALL new_pay_info_addr
|
||||||
|
MOV dword ptr [pay_info + 0x4], 0x1
|
||||||
|
MOV dword ptr [pay_info + 0x4C], 0x1
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
memcpy(&pay_info[0x1c], &transcation_id, sizeof(transcation_id));
|
||||||
|
memcpy(&pay_info[0x38], &transfer_id, sizeof(transfer_id));
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSH 0x1
|
||||||
|
SUB ESP,0x8
|
||||||
|
LEA EDX,recv_id
|
||||||
|
LEA ECX,pay_info
|
||||||
|
CALL do_confirm_addr
|
||||||
|
MOV success,EAX
|
||||||
|
ADD ESP,0xC
|
||||||
|
PUSH 0x0
|
||||||
|
LEA ECX,pay_info
|
||||||
|
CALL free_pay_info_addr
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MiscMgr::DoDownloadTask(ULONG64 msg_id) {
|
||||||
|
int success = -1;
|
||||||
|
int db_index = 0;
|
||||||
|
int local_id = DB::GetInstance().GetLocalIdByMsgId(msg_id, db_index);
|
||||||
|
if (local_id < 1) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
char chat_msg[0x2D8] = {0};
|
||||||
|
DWORD new_chat_msg_addr = base_addr_ + WX_NEW_CHAT_MSG_OFFSET;
|
||||||
|
DWORD get_chat_mgr_addr = base_addr_ + WX_CHAT_MGR_OFFSET;
|
||||||
|
DWORD pre_download_mgr_addr = base_addr_ + WX_GET_PRE_DOWNLOAD_MGR_OFFSET;
|
||||||
|
DWORD push_attach_task_addr = base_addr_ + WX_PUSH_ATTACH_TASK_OFFSET;
|
||||||
|
DWORD free_addr = base_addr_ + WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET;
|
||||||
|
DWORD get_by_local_Id_addr = base_addr_ + WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET;
|
||||||
|
DWORD get_current_data_path_addr = base_addr_ + WX_GET_CURRENT_DATA_PATH_OFFSET;
|
||||||
|
DWORD free_app_msg_info_addr = base_addr_ + WX_FREE_APP_MSG_INFO_OFFSET;
|
||||||
|
DWORD push_thumb_task_addr = base_addr_ + WX_PUSH_THUMB_TASK_OFFSET;
|
||||||
|
DWORD video_mgr_addr = base_addr_ + WX_VIDEO_MGR_OFFSET;
|
||||||
|
DWORD download_video_image_addr = base_addr_ + WX_VIDEO_MGR_OFFSET;
|
||||||
|
|
||||||
|
WeChatString current_data_path;
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
LEA ECX,current_data_path
|
||||||
|
CALL get_current_data_path_addr
|
||||||
|
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
CALL new_chat_msg_addr
|
||||||
|
|
||||||
|
CALL get_chat_mgr_addr
|
||||||
|
PUSH dword ptr [db_index]
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
PUSH dword ptr [local_id]
|
||||||
|
CALL get_by_local_Id_addr
|
||||||
|
ADD ESP,0x8
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
wstring save_path = L"";
|
||||||
|
wstring thumb_path = L"";
|
||||||
|
if (current_data_path.length > 0) {
|
||||||
|
save_path += current_data_path.ptr;
|
||||||
|
save_path += L"wxhelper";
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
DWORD type = *(DWORD *)(chat_msg + 0x38);
|
||||||
|
wchar_t *content = *(wchar_t **)(chat_msg + 0x70);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 0x3: {
|
||||||
|
save_path += L"\\image";
|
||||||
|
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
save_path = save_path +L"\\"+ to_wstring(msg_id) + L".png";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x3E:
|
||||||
|
case 0x2B: {
|
||||||
|
save_path += L"\\video";
|
||||||
|
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
thumb_path = save_path + L"\\"+ to_wstring(msg_id) + L".jpg";
|
||||||
|
save_path = save_path + L"\\"+ to_wstring(msg_id) + L".mp4";
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x31: {
|
||||||
|
save_path += L"\\file";
|
||||||
|
wcout << save_path << endl;
|
||||||
|
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
char xml_app_msg[0xC80] = {0};
|
||||||
|
DWORD new_app_msg_addr = base_addr_ + WX_APP_MSG_INFO_OFFSET;
|
||||||
|
DWORD get_xml_addr = base_addr_ + WX_GET_APP_MSG_XML_OFFSET;
|
||||||
|
WeChatString w_content(content);
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
LEA ECX,xml_app_msg
|
||||||
|
CALL new_app_msg_addr
|
||||||
|
PUSH 0x1
|
||||||
|
LEA EAX,w_content
|
||||||
|
PUSH EAX
|
||||||
|
LEA ECX,xml_app_msg
|
||||||
|
CALL get_xml_addr
|
||||||
|
MOV success,EAX
|
||||||
|
LEA ECX,xml_app_msg
|
||||||
|
CALL free_app_msg_info_addr
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
if (success != 1) {
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
WeChatString *file_name = (WeChatString *)((DWORD)xml_app_msg + 0x44);
|
||||||
|
save_path = save_path +L"\\" + to_wstring(msg_id) + L"_" +
|
||||||
|
wstring(file_name->ptr, file_name->length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
WeChatString w_save_path(save_path);
|
||||||
|
WeChatString w_thumb_path(thumb_path);
|
||||||
|
int temp =1;
|
||||||
|
memcpy(&chat_msg[0x19C], &w_thumb_path, sizeof(w_thumb_path));
|
||||||
|
memcpy(&chat_msg[0x1B0], &w_save_path, sizeof(w_save_path));
|
||||||
|
memcpy(&chat_msg[0x29C], &temp, sizeof(temp));
|
||||||
|
// note: the image has been downloaded and will not be downloaded again
|
||||||
|
// use low-level method
|
||||||
|
// this function does not work, need to modify chatmsg.
|
||||||
|
// if (type == 0x3E || type == 0x2B){
|
||||||
|
// __asm{
|
||||||
|
// PUSHAD
|
||||||
|
// PUSHFD
|
||||||
|
// CALL video_mgr_addr
|
||||||
|
// LEA ECX,chat_msg
|
||||||
|
// PUSH ECX
|
||||||
|
// MOV ECX,EAX
|
||||||
|
// CALL download_video_image_addr
|
||||||
|
// POPFD
|
||||||
|
// POPAD
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
CALL pre_download_mgr_addr
|
||||||
|
PUSH 0x1
|
||||||
|
PUSH 0x0
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
PUSH ECX
|
||||||
|
MOV ECX,EAX
|
||||||
|
CALL push_attach_task_addr
|
||||||
|
MOV success,EAX
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
PUSH 0x0
|
||||||
|
CALL free_addr
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MiscMgr::GetVoice(ULONG64 msg_id, wchar_t *dir) {
|
||||||
|
int success = -1;
|
||||||
|
string buff = DB::GetInstance().GetVoiceBuffByMsgId(msg_id);
|
||||||
|
if (buff.size() == 0) {
|
||||||
|
success = 0;
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
wstring save_path = wstring(dir);
|
||||||
|
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||||
|
success = -2;
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
save_path = save_path + L"\\" + to_wstring(msg_id) + L".amr";
|
||||||
|
HANDLE file_handle = CreateFileW(save_path.c_str(), GENERIC_ALL, 0, NULL,
|
||||||
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (file_handle == INVALID_HANDLE_VALUE) {
|
||||||
|
#ifdef _DEBUG
|
||||||
|
wcout <<" save_path =" <<save_path<<endl;
|
||||||
|
#endif
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
DWORD bytes_write = 0;
|
||||||
|
string decode = base64_decode(buff);
|
||||||
|
WriteFile(file_handle, (LPCVOID)decode.c_str(), decode.size(), &bytes_write, 0);
|
||||||
|
CloseHandle(file_handle);
|
||||||
|
success = 1;
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MiscMgr::GetImgByName(wchar_t* file_path,wchar_t* save_dir) {
|
||||||
|
wstring save_path(save_dir);
|
||||||
|
wstring orign_file_path(file_path);
|
||||||
|
if (!Utils::FindOrCreateDirectoryW(save_path.c_str())) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pos_begin = orign_file_path.find_last_of(L"\\") + 1;
|
||||||
|
int pos_end = orign_file_path.find_last_of(L".");
|
||||||
|
wstring file_name = orign_file_path.substr(pos_begin, pos_end - pos_begin);
|
||||||
|
HANDLE h_origin_file =
|
||||||
|
CreateFileW(file_path, GENERIC_READ, 0, NULL, OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
char buffer[BUFSIZE] = {0};
|
||||||
|
DWORD bytes_read = 0;
|
||||||
|
DWORD bytes_write = 0;
|
||||||
|
unsigned char magic_head[4] = {0};
|
||||||
|
wstring suffix;
|
||||||
|
short key = 0;
|
||||||
|
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
|
||||||
|
memcpy(magic_head, buffer, 3);
|
||||||
|
} else {
|
||||||
|
CloseHandle(h_origin_file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ((magic_head[0] ^ JPEG0) == (magic_head[1] ^ JPEG1)) {
|
||||||
|
key = magic_head[0] ^ JPEG0;
|
||||||
|
suffix = L".jpg";
|
||||||
|
} else if ((magic_head[0] ^ PNG1) == (magic_head[1] ^ PNG2)) {
|
||||||
|
key = magic_head[0] ^ PNG1;
|
||||||
|
suffix = L".png";
|
||||||
|
} else if ((magic_head[0] ^ GIF0) == (magic_head[1] ^ GIF1)) {
|
||||||
|
key = magic_head[0] ^ GIF0;
|
||||||
|
suffix = L".gif";
|
||||||
|
} else if ((magic_head[0] ^ BMP0) == (magic_head[1] ^ BMP1)) {
|
||||||
|
key = magic_head[0] ^ BMP0;
|
||||||
|
suffix = L".bmp";
|
||||||
|
} else {
|
||||||
|
key = -1;
|
||||||
|
suffix = L".dat";
|
||||||
|
}
|
||||||
|
wstring save_img_path = save_path + L"\\" + file_name + suffix;
|
||||||
|
HANDLE save_img = CreateFileW(save_img_path.c_str(), GENERIC_ALL, 0, NULL,
|
||||||
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||||
|
if (save_img == INVALID_HANDLE_VALUE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (key > 0) {
|
||||||
|
for (unsigned int i = 0; i < bytes_read; i++) {
|
||||||
|
buffer[i]^=key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
|
||||||
|
CloseHandle(h_origin_file);
|
||||||
|
CloseHandle(save_img);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (ReadFile(h_origin_file, buffer, BUFSIZE, &bytes_read, NULL)) {
|
||||||
|
if (key > 0) {
|
||||||
|
for (unsigned int i = 0; i < bytes_read; i++) {
|
||||||
|
buffer[i] ^= key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!WriteFile(save_img, (LPCVOID)buffer, bytes_read, &bytes_write, 0)) {
|
||||||
|
CloseHandle(h_origin_file);
|
||||||
|
CloseHandle(save_img);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (bytes_read == BUFSIZE);
|
||||||
|
CloseHandle(h_origin_file);
|
||||||
|
CloseHandle(save_img);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MiscMgr::SearchContactNetScene(wchar_t *keyword,UserInfo ** user) {
|
||||||
|
int success = -1;
|
||||||
|
hooks::HookSearchContact();
|
||||||
|
hooks::DeleteUserInfoCache();
|
||||||
|
DWORD search_contact_mgr_addr = base_addr_ + WX_SEARCH_CONTACT_MGR_OFFSET;
|
||||||
|
DWORD search_contact_addr = base_addr_ + WX_SEARCH_CONTACT_OFFSET;
|
||||||
|
WeChatString key(keyword);
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
pushad;
|
||||||
|
pushfd;
|
||||||
|
call search_contact_mgr_addr;
|
||||||
|
lea ebx, key;
|
||||||
|
push ebx;
|
||||||
|
mov ecx, eax;
|
||||||
|
call search_contact_addr;
|
||||||
|
popfd;
|
||||||
|
popad;
|
||||||
|
}
|
||||||
|
success = 1;
|
||||||
|
while (hooks::userinfo.error_code == 1 && hooks::user_info_flag_) {
|
||||||
|
Sleep(20);
|
||||||
|
}
|
||||||
|
if (hooks::userinfo.error_code == 0) {
|
||||||
|
while (hooks::userinfo.over == false && hooks::user_info_flag_) {
|
||||||
|
Sleep(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*user= &hooks::userinfo;
|
||||||
|
LOG(INFO)<<"user:" <<user;
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wxhelper
|
24
src/misc_mgr.h
Normal file
24
src/misc_mgr.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef WXHELPER_MISC_MGR_H_
|
||||||
|
#define WXHELPER_MISC_MGR_H_
|
||||||
|
#include <string>
|
||||||
|
#include "Windows.h"
|
||||||
|
#include "base_mgr.h"
|
||||||
|
#include "wechat_function.h"
|
||||||
|
namespace wxhelper {
|
||||||
|
class MiscMgr :public BaseMgr{
|
||||||
|
public:
|
||||||
|
MiscMgr(DWORD base);
|
||||||
|
~MiscMgr();
|
||||||
|
int SendPatMsg(wchar_t* chat_room_id, wchar_t* wxid);
|
||||||
|
int DoOCRTask(wchar_t* img_path, std::string& result);
|
||||||
|
int DoConfirmReceipt(wchar_t* wxid, wchar_t* transcationid,
|
||||||
|
wchar_t* transferid);
|
||||||
|
int DoDownloadTask(ULONG64 msg_id);
|
||||||
|
|
||||||
|
int GetVoice(ULONG64 msg_id, wchar_t* dir);
|
||||||
|
int GetImgByName(wchar_t* file_path,wchar_t* save_dir);
|
||||||
|
int SearchContactNetScene(wchar_t *keyword,UserInfo ** user);
|
||||||
|
};
|
||||||
|
} // namespace wxhelper
|
||||||
|
|
||||||
|
#endif
|
195
src/new_sqlite3.h
Normal file
195
src/new_sqlite3.h
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
#ifndef NEW_SQLITE3_H_
|
||||||
|
#define NEW_SQLITE3_H_
|
||||||
|
#include "Windows.h"
|
||||||
|
#define SQLITE_OK 0 /* Successful result */
|
||||||
|
/* beginning-of-error-codes */
|
||||||
|
#define SQLITE_ERROR 1 /* Generic error */
|
||||||
|
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
|
||||||
|
#define SQLITE_PERM 3 /* Access permission denied */
|
||||||
|
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
|
||||||
|
#define SQLITE_BUSY 5 /* The database file is locked */
|
||||||
|
#define SQLITE_LOCKED 6 /* A table in the database is locked */
|
||||||
|
#define SQLITE_NOMEM 7 /* A malloc() failed */
|
||||||
|
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
|
||||||
|
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
|
||||||
|
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
|
||||||
|
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
|
||||||
|
#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */
|
||||||
|
#define SQLITE_FULL 13 /* Insertion failed because database is full */
|
||||||
|
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
|
||||||
|
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
|
||||||
|
#define SQLITE_EMPTY 16 /* Internal use only */
|
||||||
|
#define SQLITE_SCHEMA 17 /* The database schema changed */
|
||||||
|
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
|
||||||
|
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
|
||||||
|
#define SQLITE_MISMATCH 20 /* Data type mismatch */
|
||||||
|
#define SQLITE_MISUSE 21 /* Library used incorrectly */
|
||||||
|
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
|
||||||
|
#define SQLITE_AUTH 23 /* Authorization denied */
|
||||||
|
#define SQLITE_FORMAT 24 /* Not used */
|
||||||
|
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
|
||||||
|
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
|
||||||
|
#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
|
||||||
|
#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
|
||||||
|
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
|
||||||
|
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
|
||||||
|
/* end-of-error-codes */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI3REF: Extended Result Codes
|
||||||
|
** KEYWORDS: {extended result code definitions}
|
||||||
|
**
|
||||||
|
** In its default configuration, SQLite API routines return one of 30 integer
|
||||||
|
** [result codes]. However, experience has shown that many of
|
||||||
|
** these result codes are too coarse-grained. They do not provide as
|
||||||
|
** much information about problems as programmers might like. In an effort to
|
||||||
|
** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8]
|
||||||
|
** and later) include
|
||||||
|
** support for additional result codes that provide more detailed information
|
||||||
|
** about errors. These [extended result codes] are enabled or disabled
|
||||||
|
** on a per database connection basis using the
|
||||||
|
** [sqlite3_extended_result_codes()] API. Or, the extended code for
|
||||||
|
** the most recent error can be obtained using
|
||||||
|
** [sqlite3_extended_errcode()].
|
||||||
|
*/
|
||||||
|
#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1 << 8))
|
||||||
|
#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2 << 8))
|
||||||
|
#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3 << 8))
|
||||||
|
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1 << 8))
|
||||||
|
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2 << 8))
|
||||||
|
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3 << 8))
|
||||||
|
#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4 << 8))
|
||||||
|
#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5 << 8))
|
||||||
|
#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6 << 8))
|
||||||
|
#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7 << 8))
|
||||||
|
#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8 << 8))
|
||||||
|
#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9 << 8))
|
||||||
|
#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10 << 8))
|
||||||
|
#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11 << 8))
|
||||||
|
#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12 << 8))
|
||||||
|
#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13 << 8))
|
||||||
|
#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14 << 8))
|
||||||
|
#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15 << 8))
|
||||||
|
#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16 << 8))
|
||||||
|
#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17 << 8))
|
||||||
|
#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18 << 8))
|
||||||
|
#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19 << 8))
|
||||||
|
#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20 << 8))
|
||||||
|
#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21 << 8))
|
||||||
|
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22 << 8))
|
||||||
|
#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23 << 8))
|
||||||
|
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24 << 8))
|
||||||
|
#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25 << 8))
|
||||||
|
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26 << 8))
|
||||||
|
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27 << 8))
|
||||||
|
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28 << 8))
|
||||||
|
#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29 << 8))
|
||||||
|
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30 << 8))
|
||||||
|
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31 << 8))
|
||||||
|
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32 << 8))
|
||||||
|
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33 << 8))
|
||||||
|
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1 << 8))
|
||||||
|
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2 << 8))
|
||||||
|
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1 << 8))
|
||||||
|
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2 << 8))
|
||||||
|
#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5 << 8)) /* Not Used */
|
||||||
|
#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6 << 8))
|
||||||
|
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1 << 8))
|
||||||
|
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2 << 8))
|
||||||
|
#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3 << 8))
|
||||||
|
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1 << 8))
|
||||||
|
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2 << 8))
|
||||||
|
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3 << 8))
|
||||||
|
#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4 << 8))
|
||||||
|
#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5 << 8))
|
||||||
|
#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6 << 8))
|
||||||
|
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT | (10 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT | (11 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT | (12 << 8))
|
||||||
|
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1 << 8))
|
||||||
|
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2 << 8))
|
||||||
|
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1 << 8))
|
||||||
|
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1 << 8))
|
||||||
|
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1 << 8))
|
||||||
|
#define SQLITE_OK_SYMLINK (SQLITE_OK | (2 << 8)) /* internal use only */
|
||||||
|
|
||||||
|
|
||||||
|
#define SQLITE_INTEGER 1
|
||||||
|
#define SQLITE_FLOAT 2
|
||||||
|
#define SQLITE_BLOB 4
|
||||||
|
#define SQLITE_NULL 5
|
||||||
|
#define SQLITE_TEXT 3
|
||||||
|
|
||||||
|
#define SQLITE3_EXEC_OFFSET 0x1e24f70
|
||||||
|
#define SQLITE3_BACKUP_INIT_OFFSET 0x1dea900
|
||||||
|
#define SQLITE3_PREPARE_OFFSET 0x1e2b8c0
|
||||||
|
#define SQLITE3_OPEN_OFFSET 0x1e598b0
|
||||||
|
#define SQLITE3_BACKUP_STEP_OFFSET 0x1dead00
|
||||||
|
#define SQLITE3_BACKUP_REMAINING_OFFSET 0x1deb440
|
||||||
|
#define SQLITE3_BACKUP_PAGECOUNT_OFFSET 0x1deb450
|
||||||
|
#define SQLITE3_BACKUP_FINISH_OFFSET 0x1deb340
|
||||||
|
#define SQLITE3_SLEEP_OFFSET 0x1e5a0f0
|
||||||
|
#define SQLITE3_ERRCODE_OFFSET 0x1e58550
|
||||||
|
#define SQLITE3_CLOSE_OFFSET 0x1e56cd0
|
||||||
|
#define SQLITE3_STEP_OFFSET 0x1df3770
|
||||||
|
#define SQLITE3_COLUMN_COUNT_OFFSET 0x1df3c80
|
||||||
|
#define SQLITE3_COLUMN_NAME_OFFSET 0x1df4570
|
||||||
|
#define SQLITE3_COLUMN_TYPE_OFFSET 0x1df4410
|
||||||
|
#define SQLITE3_COLUMN_BLOB_OFFSET 0x1df3cc0
|
||||||
|
#define SQLITE3_COLUMN_BYTES_OFFSET 0x1df3da0
|
||||||
|
#define SQLITE3_FINALIZE_OFFSET 0x1df2740
|
||||||
|
|
||||||
|
typedef int (*Sqlite3_callback)(void*, int, char**, char**);
|
||||||
|
|
||||||
|
typedef int(__cdecl* Sqlite3_exec)(DWORD, /* An open database */
|
||||||
|
const char* sql, /* SQL to be evaluated */
|
||||||
|
Sqlite3_callback, /* Callback function */
|
||||||
|
void*, /* 1st argument to callback */
|
||||||
|
char** errmsg /* Error msg written here */
|
||||||
|
);
|
||||||
|
typedef DWORD(__cdecl* Sqlite3_backup_init)(
|
||||||
|
DWORD* pDest, /* Destination database handle */
|
||||||
|
const char* zDestName, /* Destination database name */
|
||||||
|
DWORD* pSource, /* Source database handle */
|
||||||
|
const char* zSourceName /* Source database name */
|
||||||
|
);
|
||||||
|
typedef int(__cdecl* Sqlite3_prepare)(
|
||||||
|
DWORD db, /* Database handle */
|
||||||
|
const char* zSql, /* SQL statement, UTF-8 encoded */
|
||||||
|
int nByte, /* Maximum length of zSql in bytes. */
|
||||||
|
DWORD** ppStmt, /* OUT: Statement handle */
|
||||||
|
const char** pzTail /* OUT: Pointer to unused portion of zSql */
|
||||||
|
);
|
||||||
|
typedef int(__cdecl* Sqlite3_open)(const char* filename, DWORD** ppDb);
|
||||||
|
typedef int(__cdecl* Sqlite3_backup_step)(DWORD* p, int nPage);
|
||||||
|
typedef int(__cdecl* Sqlite3_backup_remaining)(DWORD* p);
|
||||||
|
typedef int(__cdecl* Sqlite3_backup_pagecount)(DWORD* p);
|
||||||
|
typedef int(__cdecl* Sqlite3_backup_finish)(DWORD* p);
|
||||||
|
typedef int(__cdecl* Sqlite3_sleep)(int);
|
||||||
|
typedef int(__cdecl* Sqlite3_errcode)(DWORD* db);
|
||||||
|
typedef int(__cdecl* Sqlite3_close)(DWORD*);
|
||||||
|
|
||||||
|
typedef int(__cdecl* Sqlite3_step)(DWORD*);
|
||||||
|
typedef int(__cdecl* Sqlite3_column_count)(DWORD* pStmt);
|
||||||
|
typedef const char*(__cdecl* Sqlite3_column_name)(DWORD*, int N);
|
||||||
|
typedef int(__cdecl* Sqlite3_column_type)(DWORD*, int iCol);
|
||||||
|
typedef const void*(__cdecl* Sqlite3_column_blob)(DWORD*, int iCol);
|
||||||
|
typedef int(__cdecl* Sqlite3_column_bytes)(DWORD*, int iCol);
|
||||||
|
typedef int(__cdecl* Sqlite3_finalize)(DWORD* pStmt);
|
||||||
|
|
||||||
|
#endif
|
22
src/pch.h
Normal file
22
src/pch.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef PCH_H
|
||||||
|
#define PCH_H
|
||||||
|
|
||||||
|
|
||||||
|
#define GLOG_NO_ABBREVIATED_SEVERITIES
|
||||||
|
#include "framework.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <strstream>
|
||||||
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <time.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include "Windows.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#endif // PCH_H
|
||||||
|
|
||||||
|
|
178
src/send_message_mgr.cc
Normal file
178
src/send_message_mgr.cc
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "send_message_mgr.h"
|
||||||
|
|
||||||
|
#include "easylogging++.h"
|
||||||
|
|
||||||
|
#include "wechat_function.h"
|
||||||
|
#include "db.h"
|
||||||
|
|
||||||
|
namespace wxhelper {
|
||||||
|
SendMessageMgr::SendMessageMgr(DWORD base):BaseMgr(base) {}
|
||||||
|
SendMessageMgr::~SendMessageMgr() {}
|
||||||
|
int SendMessageMgr::SendText(wchar_t* wxid, wchar_t* msg) {
|
||||||
|
int success = -1;
|
||||||
|
WeChatString to_user(wxid);
|
||||||
|
WeChatString text_msg(msg);
|
||||||
|
wchar_t** msg_pptr = &text_msg.ptr;
|
||||||
|
DWORD base = Utils::GetWeChatWinBase();
|
||||||
|
DWORD send_message_mgr_addr = base + WX_SEND_MESSAGE_MGR_OFFSET;
|
||||||
|
DWORD send_text_msg_addr = base + WX_SEND_TEXT_OFFSET;
|
||||||
|
DWORD free_chat_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
|
||||||
|
char chat_msg[0x2D8] = {0};
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
CALL send_message_mgr_addr
|
||||||
|
PUSH 0x0
|
||||||
|
PUSH 0x0
|
||||||
|
PUSH 0x0
|
||||||
|
PUSH 0x1
|
||||||
|
PUSH 0x0
|
||||||
|
MOV EAX,msg_pptr
|
||||||
|
PUSH EAX
|
||||||
|
LEA EDX,to_user
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
CALL send_text_msg_addr
|
||||||
|
MOV success,EAX
|
||||||
|
ADD ESP,0x18
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
CALL free_chat_msg_addr
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
LOG_IF((success == -1), ERROR) << "SendText fail";
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
int SendMessageMgr::SendAtText(wchar_t* chat_room_id, wchar_t** wxids, int len,
|
||||||
|
wchar_t* msg) {
|
||||||
|
int success = -1;
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
int SendMessageMgr::SendImage(wchar_t* wxid, wchar_t* image_path) {
|
||||||
|
int success = -1;
|
||||||
|
WeChatString to_user(wxid);
|
||||||
|
WeChatString path(image_path);
|
||||||
|
char chat_msg[0x2D8] = {0};
|
||||||
|
DWORD base = Utils::GetWeChatWinBase();
|
||||||
|
DWORD send_message_mgr_addr = base + WX_SEND_MESSAGE_MGR_OFFSET;
|
||||||
|
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
|
||||||
|
DWORD send_image_msg_addr = base + WX_SEND_IMAGE_OFFSET;
|
||||||
|
DWORD free_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
|
||||||
|
DWORD temp = 0;
|
||||||
|
WeChatString null_obj = {0};
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
CALL send_message_mgr_addr
|
||||||
|
SUB ESP,0x14
|
||||||
|
MOV temp,EAX
|
||||||
|
LEA EAX,null_obj
|
||||||
|
MOV ECX,ESP
|
||||||
|
LEA EDI,path
|
||||||
|
PUSH EAX
|
||||||
|
CALL init_chat_msg_addr
|
||||||
|
MOV ECX,dword ptr [temp]
|
||||||
|
LEA EAX,to_user
|
||||||
|
PUSH EDI
|
||||||
|
PUSH EAX
|
||||||
|
LEA EAX,chat_msg
|
||||||
|
PUSH EAX
|
||||||
|
CALL send_image_msg_addr
|
||||||
|
MOV success,EAX
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
CALL free_msg_addr
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
LOG_IF((success == -1), ERROR) << "SendImage fail";
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
int SendMessageMgr::SendFile(wchar_t* wxid, wchar_t* file_path) {
|
||||||
|
int success = -1;
|
||||||
|
WeChatString to_user(wxid);
|
||||||
|
WeChatString path(file_path);
|
||||||
|
char chat_msg[0x2D8] = {0};
|
||||||
|
DWORD base = Utils::GetWeChatWinBase();
|
||||||
|
DWORD app_msg_mgr_addr = base + WX_APP_MSG_MGR_OFFSET;
|
||||||
|
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
|
||||||
|
DWORD send_file_addr = base + WX_SEND_FILE_OFFSET;
|
||||||
|
DWORD free_msg_addr = base + WX_FREE_CHAT_MSG_OFFSET;
|
||||||
|
DWORD temp = 0;
|
||||||
|
WeChatString null_obj = {0};
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
CALL app_msg_mgr_addr
|
||||||
|
SUB ESP,0x14
|
||||||
|
MOV temp,EAX
|
||||||
|
LEA EAX,null_obj
|
||||||
|
MOV ECX,ESP
|
||||||
|
PUSH EAX
|
||||||
|
CALL init_chat_msg_addr
|
||||||
|
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,path
|
||||||
|
MOV ECX,ESP
|
||||||
|
PUSH EAX
|
||||||
|
CALL init_chat_msg_addr
|
||||||
|
SUB ESP,0x14
|
||||||
|
LEA EAX,to_user
|
||||||
|
MOV ECX,ESP
|
||||||
|
PUSH EAX
|
||||||
|
CALL init_chat_msg_addr
|
||||||
|
MOV ECX,dword ptr [temp]
|
||||||
|
LEA EAX,chat_msg
|
||||||
|
PUSH EAX
|
||||||
|
CALL send_file_addr
|
||||||
|
MOV AL,byte ptr [eax + 0x38]
|
||||||
|
MOVZX EAX,AL
|
||||||
|
MOV success,EAX
|
||||||
|
LEA ECX,chat_msg
|
||||||
|
CALL free_msg_addr
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
if (success == 0x31) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
LOG_IF((success == -1), ERROR) << "SendFile fail";
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SendMessageMgr::ForwardMsg(wchar_t* wxid, unsigned long long msgid) {
|
||||||
|
int success = 0;
|
||||||
|
|
||||||
|
int db_index = 0;
|
||||||
|
int localid = DB::GetInstance().GetLocalIdByMsgId(msgid, db_index);
|
||||||
|
|
||||||
|
if (localid == 0) return 0;
|
||||||
|
WeChatString to_user(wxid);
|
||||||
|
DWORD base = Utils::GetWeChatWinBase();
|
||||||
|
DWORD forward_msg_addr = base + WX_FORWARD_MSG_OFFSET;
|
||||||
|
DWORD init_chat_msg_addr = base + WX_INIT_CHAT_MSG_OFFSET;
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
PUSHFD
|
||||||
|
MOV EDX, DWORD PTR [db_index]
|
||||||
|
PUSH EDX
|
||||||
|
MOV EAX, DWORD PTR [localid]
|
||||||
|
PUSH EAX
|
||||||
|
SUB ESP,0x14
|
||||||
|
MOV ECX,ESP
|
||||||
|
LEA ESI,to_user
|
||||||
|
PUSH ESI
|
||||||
|
CALL init_chat_msg_addr
|
||||||
|
XOR ECX,ECX
|
||||||
|
CALL forward_msg_addr
|
||||||
|
MOVZX EAX,AL
|
||||||
|
MOV success,EAX
|
||||||
|
ADD ESP,0x1c
|
||||||
|
POPFD
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
} // namespace wxhelper
|
18
src/send_message_mgr.h
Normal file
18
src/send_message_mgr.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef WXHELPER_SEND_MESSAGE_MGR_H_
|
||||||
|
#define WXHELPER_SEND_MESSAGE_MGR_H_
|
||||||
|
#include "base_mgr.h"
|
||||||
|
namespace wxhelper {
|
||||||
|
class SendMessageMgr:public BaseMgr {
|
||||||
|
public:
|
||||||
|
explicit SendMessageMgr(DWORD base);
|
||||||
|
~SendMessageMgr();
|
||||||
|
int SendText(wchar_t* wxid, wchar_t* msg);
|
||||||
|
int SendAtText(wchar_t* chat_room_id, wchar_t** wxids, int len, wchar_t* msg);
|
||||||
|
int SendImage(wchar_t *wxid, wchar_t *image_path);
|
||||||
|
int SendFile(wchar_t *wxid, wchar_t *file_path);
|
||||||
|
int ForwardMsg(wchar_t *wxid, unsigned long long msgid);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
} // namespace wxhelper
|
||||||
|
#endif
|
21
src/singleton.h
Normal file
21
src/singleton.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef WXHELPER_SINGLETON_H_
|
||||||
|
#define WXHELPER_SINGLETON_H_
|
||||||
|
template <typename T>
|
||||||
|
class Singleton {
|
||||||
|
protected:
|
||||||
|
Singleton() {}
|
||||||
|
~Singleton() {}
|
||||||
|
|
||||||
|
Singleton(const Singleton&) = delete;
|
||||||
|
Singleton& operator=(const Singleton&) = delete;
|
||||||
|
|
||||||
|
Singleton(Singleton&&) = delete;
|
||||||
|
Singleton& operator=(Singleton&&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static T& GetInstance() {
|
||||||
|
static T instance{};
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
52
src/sns_mgr.cc
Normal file
52
src/sns_mgr.cc
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "sns_mgr.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "wechat_function.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace wxhelper {
|
||||||
|
SNSMgr::SNSMgr(DWORD base):BaseMgr(base) {}
|
||||||
|
SNSMgr::~SNSMgr() {}
|
||||||
|
int SNSMgr::GetFirstPage() {
|
||||||
|
int success = -1;
|
||||||
|
DWORD sns_data_mgr_addr = base_addr_ + WX_SNS_DATA_MGR_OFFSET;
|
||||||
|
DWORD get_first_page_addr = base_addr_ + WX_SNS_GET_FIRST_PAGE_OFFSET;
|
||||||
|
|
||||||
|
char buff[0xB44] = {};
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
CALL sns_data_mgr_addr
|
||||||
|
PUSH 0x1
|
||||||
|
LEA ECX,buff
|
||||||
|
PUSH ECX
|
||||||
|
MOV ECX,EAX
|
||||||
|
CALL get_first_page_addr
|
||||||
|
MOV success,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
int SNSMgr::GetNextPage(ULONG64 sns_id) {
|
||||||
|
int success = -1;
|
||||||
|
DWORD sns_data_mgr_addr = base_addr_ + WX_SNS_DATA_MGR_OFFSET;
|
||||||
|
DWORD get_next_page_addr = base_addr_ + WX_SNS_GET_NEXT_PAGE_OFFSET;
|
||||||
|
VectorInner temp = {};
|
||||||
|
__asm {
|
||||||
|
PUSHAD
|
||||||
|
CALL sns_data_mgr_addr
|
||||||
|
LEA ECX,temp
|
||||||
|
PUSH ECX
|
||||||
|
MOV EBX,dword ptr [sns_id + 0x4]
|
||||||
|
PUSH EBX
|
||||||
|
MOV EDI,dword ptr [sns_id ]
|
||||||
|
PUSH EDI
|
||||||
|
MOV ECX,EAX
|
||||||
|
CALL get_next_page_addr
|
||||||
|
MOV success,EAX
|
||||||
|
POPAD
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
} // namespace wxhelper
|
14
src/sns_mgr.h
Normal file
14
src/sns_mgr.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef WXHELPER_SNS_MGR_H_
|
||||||
|
#define WXHELPER_SNS_MGR_H_
|
||||||
|
#include "Windows.h"
|
||||||
|
#include "base_mgr.h"
|
||||||
|
namespace wxhelper{
|
||||||
|
class SNSMgr:public BaseMgr{
|
||||||
|
public:
|
||||||
|
explicit SNSMgr(DWORD base);
|
||||||
|
~SNSMgr();
|
||||||
|
int GetFirstPage();
|
||||||
|
int GetNextPage(ULONG64 sns_id);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
177
src/utils.cc
Normal file
177
src/utils.cc
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace wxhelper {
|
||||||
|
std::wstring Utils::UTF8ToWstring(const std::string &str) {
|
||||||
|
return Utils::AnsiToWstring(str, CP_UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Utils::WstringToUTF8(const std::wstring &str) {
|
||||||
|
return Utils::WstringToAnsi(str, CP_UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring Utils::AnsiToWstring(const std::string &input, DWORD locale) {
|
||||||
|
int wchar_len = MultiByteToWideChar(locale, 0, input.c_str(), -1, NULL, 0);
|
||||||
|
if (wchar_len > 0) {
|
||||||
|
std::vector<wchar_t> temp(wchar_len);
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, input.c_str(), -1, &temp[0], wchar_len);
|
||||||
|
return std::wstring(&temp[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::wstring();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Utils::WstringToAnsi(const std::wstring &input, DWORD locale) {
|
||||||
|
int char_len = WideCharToMultiByte(locale, 0, input.c_str(), -1, 0, 0, 0, 0);
|
||||||
|
if (char_len > 0) {
|
||||||
|
std::vector<char> temp(char_len);
|
||||||
|
WideCharToMultiByte(locale, 0, input.c_str(), -1, &temp[0], char_len, 0, 0);
|
||||||
|
return std::string(&temp[0]);
|
||||||
|
}
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD Utils::GetWeChatWinBase() {
|
||||||
|
return (DWORD)GetModuleHandleA("WeChatWin.dll");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Utils::CreateConsole() {
|
||||||
|
if (AllocConsole()) {
|
||||||
|
AttachConsole(GetCurrentProcessId());
|
||||||
|
FILE *retStream;
|
||||||
|
freopen_s(&retStream, "CONOUT$", "w", stdout);
|
||||||
|
if (!retStream) throw std::runtime_error("Stdout redirection failed.");
|
||||||
|
freopen_s(&retStream, "CONOUT$", "w", stderr);
|
||||||
|
if (!retStream) throw std::runtime_error("Stderr redirection failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::CloseConsole() {
|
||||||
|
fclose(stdin);
|
||||||
|
fclose(stdout);
|
||||||
|
fclose(stderr);
|
||||||
|
FreeConsole();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Utils::EncodeHexString(const std::string &str) {
|
||||||
|
const std::string hex_table = "0123456789abcdef";
|
||||||
|
std::string sb;
|
||||||
|
for (int i = 0; i < str.length(); i++) {
|
||||||
|
sb += hex_table.at((str[i] & 0xf0) >> 4);
|
||||||
|
sb += hex_table.at((str[i] & 0x0f) >> 0);
|
||||||
|
}
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Utils::Hex2String(const std::string &hex_str) {
|
||||||
|
std::string ret;
|
||||||
|
const std::string hex_table = "0123456789abcdef";
|
||||||
|
for (int i = 0; i < hex_str.length(); i += 2) {
|
||||||
|
ret += BYTE(hex_table.find(hex_str.at(i)) << 4 |
|
||||||
|
hex_table.find(hex_str.at(i + 1)));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Utils::Bytes2Hex(const BYTE *bytes, const int length) {
|
||||||
|
if (bytes == NULL) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
std::string buff;
|
||||||
|
const int len = length;
|
||||||
|
for (int j = 0; j < len; j++) {
|
||||||
|
int high = bytes[j] / 16, low = bytes[j] % 16;
|
||||||
|
buff += (high < 10) ? ('0' + high) : ('a' + high - 10);
|
||||||
|
buff += (low < 10) ? ('0' + low) : ('a' + low - 10);
|
||||||
|
}
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::Hex2Bytes(const std::string &hex, BYTE *bytes) {
|
||||||
|
int byte_len = hex.length() / 2;
|
||||||
|
std::string str;
|
||||||
|
unsigned int n;
|
||||||
|
for (int i = 0; i < byte_len; i++) {
|
||||||
|
str = hex.substr(i * 2, 2);
|
||||||
|
sscanf_s(str.c_str(), "%x", &n);
|
||||||
|
bytes[i] = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool Utils::IsDigit(std::string str) {
|
||||||
|
if (str.length() == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (auto it : str) {
|
||||||
|
if (it < '0' || it > '9') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Utils::FindOrCreateDirectoryW(const wchar_t *path) {
|
||||||
|
WIN32_FIND_DATAW fd;
|
||||||
|
HANDLE hFind = ::FindFirstFileW(path, &fd);
|
||||||
|
if (hFind != INVALID_HANDLE_VALUE && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||||
|
FindClose(hFind);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!::CreateDirectoryW(path, NULL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::HookAnyAddress(DWORD hook_addr, LPVOID jmp_addr, char *origin) {
|
||||||
|
BYTE jmp_code[5] = {0};
|
||||||
|
jmp_code[0] = 0xE9;
|
||||||
|
*(DWORD *)&jmp_code[1] = (DWORD)jmp_addr - hook_addr - 5;
|
||||||
|
DWORD old_protext = 0;
|
||||||
|
VirtualProtect((LPVOID)hook_addr, 5, PAGE_EXECUTE_READWRITE, &old_protext);
|
||||||
|
ReadProcessMemory(GetCurrentProcess(), (LPVOID)hook_addr, origin, 5, 0);
|
||||||
|
memcpy((void *)hook_addr, jmp_code, 5);
|
||||||
|
VirtualProtect((LPVOID)hook_addr, 5, old_protext, &old_protext);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::UnHookAnyAddress(DWORD hook_addr, char *origin) {
|
||||||
|
DWORD old_protext = 0;
|
||||||
|
VirtualProtect((LPVOID)hook_addr, 5, PAGE_EXECUTE_READWRITE, &old_protext);
|
||||||
|
WriteProcessMemory(GetCurrentProcess(), (LPVOID)hook_addr, origin, 5, 0);
|
||||||
|
VirtualProtect((LPVOID)hook_addr, 5, old_protext, &old_protext);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring Utils::GetTimeW(long long timestamp) {
|
||||||
|
wchar_t *wstr = new wchar_t[20];
|
||||||
|
memset(wstr, 0, 20 * 2);
|
||||||
|
tm tm_out;
|
||||||
|
localtime_s(&tm_out, ×tamp);
|
||||||
|
swprintf_s(wstr, 20, L"%04d-%02d-%02d %02d:%02d:%02d", 1900 + tm_out.tm_year,
|
||||||
|
tm_out.tm_mon + 1, tm_out.tm_mday, tm_out.tm_hour, tm_out.tm_min,
|
||||||
|
tm_out.tm_sec);
|
||||||
|
std::wstring str_time(wstr);
|
||||||
|
delete[] wstr;
|
||||||
|
return str_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Utils::WCharToUTF8(wchar_t *wstr) {
|
||||||
|
int c_size = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, FALSE);
|
||||||
|
if (c_size > 0) {
|
||||||
|
char *buffer = new char[c_size];
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, buffer, c_size, NULL, FALSE);
|
||||||
|
std::string str(buffer);
|
||||||
|
delete[] buffer;
|
||||||
|
buffer = NULL;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wxhelper
|
77
src/utils.h
Normal file
77
src/utils.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#ifndef WXHELPER_UTILS_H_
|
||||||
|
#define WXHELPER_UTILS_H_
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#define STRING2INT(str) (Utils::IsDigit(str) ? stoi(str) : 0)
|
||||||
|
#define WS2LPWS(wstr) (LPWSTR) wstr.c_str()
|
||||||
|
#define READ_WSTRING(addr, offset) ((*(DWORD *)(addr + offset + 0x4) == 0) ? std::wstring(L"") : std::wstring((wchar_t *)(*(DWORD *)(addr + offset)), *(DWORD *)(addr + offset + 0x4)))
|
||||||
|
|
||||||
|
|
||||||
|
namespace wxhelper {
|
||||||
|
|
||||||
|
class Utils {
|
||||||
|
public:
|
||||||
|
static std::wstring UTF8ToWstring(const std::string &str);
|
||||||
|
|
||||||
|
static std::string WstringToUTF8(const std::wstring &str);
|
||||||
|
|
||||||
|
static std::wstring AnsiToWstring(const std::string &input,
|
||||||
|
DWORD locale = CP_ACP);
|
||||||
|
|
||||||
|
static std::string WstringToAnsi(const std::wstring &input,
|
||||||
|
DWORD locale = CP_ACP);
|
||||||
|
|
||||||
|
static DWORD GetWeChatWinBase();
|
||||||
|
|
||||||
|
static bool CreateConsole();
|
||||||
|
|
||||||
|
static void CloseConsole();
|
||||||
|
|
||||||
|
static std::string EncodeHexString(const std::string &str);
|
||||||
|
|
||||||
|
static std::string Hex2String(const std::string &hex_str);
|
||||||
|
|
||||||
|
static std::string Bytes2Hex(const BYTE *bytes, const int length);
|
||||||
|
|
||||||
|
static void Hex2Bytes(const std::string &hex, BYTE *bytes);
|
||||||
|
|
||||||
|
static bool IsDigit(std::string str);
|
||||||
|
|
||||||
|
static bool FindOrCreateDirectoryW(const wchar_t *path);
|
||||||
|
|
||||||
|
static void HookAnyAddress(DWORD hook_addr, LPVOID jmp_addr, char *origin);
|
||||||
|
static void UnHookAnyAddress(DWORD hook_addr, char *origin);
|
||||||
|
static std::wstring GetTimeW(long long timestamp);
|
||||||
|
|
||||||
|
static std::string WCharToUTF8(wchar_t *wstr);
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
static std::vector<T1> split(T1 str, T2 letter) {
|
||||||
|
std::vector<T1> arr;
|
||||||
|
size_t pos;
|
||||||
|
while ((pos = str.find_first_of(letter)) != T1::npos) {
|
||||||
|
T1 str1 = str.substr(0, pos);
|
||||||
|
arr.push_back(str1);
|
||||||
|
str = str.substr(pos + 1, str.length() - pos - 1);
|
||||||
|
}
|
||||||
|
arr.push_back(str);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
static T1 replace(T1 source, T2 replaced, T1 replaceto) {
|
||||||
|
std::vector<T1> v_arr = split(source, replaced);
|
||||||
|
if (v_arr.size() < 2) return source;
|
||||||
|
T1 temp;
|
||||||
|
for (unsigned int i = 0; i < v_arr.size() - 1; i++) {
|
||||||
|
temp += v_arr[i];
|
||||||
|
temp += replaceto;
|
||||||
|
}
|
||||||
|
temp += v_arr[v_arr.size() - 1];
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace wxhelper
|
||||||
|
#endif
|
772
src/wechat_function.h
Normal file
772
src/wechat_function.h
Normal file
@ -0,0 +1,772 @@
|
|||||||
|
#ifndef WXHELPER_WECHAT_FUNCTION_H_
|
||||||
|
#define WXHELPER_WECHAT_FUNCTION_H_
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// snsDataMgr
|
||||||
|
#define WX_SNS_DATA_MGR_OFFSET 0xc39680
|
||||||
|
// chatRoomMgr
|
||||||
|
#define WX_CHAT_ROOM_MGR_OFFSET 0x78cf20
|
||||||
|
// contactMgr
|
||||||
|
#define WX_CONTACT_MGR_OFFSET 0x75a4a0
|
||||||
|
// syncMgr
|
||||||
|
#define WX_SYNC_MGR_OFFSET 0xa87fd0
|
||||||
|
// preDownloadMgr
|
||||||
|
#define WX_GET_PRE_DOWNLOAD_MGR_OFFSET 0x80f110
|
||||||
|
// chatMgr
|
||||||
|
#define WX_CHAT_MGR_OFFSET 0x792700
|
||||||
|
// videoMgr
|
||||||
|
#define WX_VIDEO_MGR_OFFSET 0x829820
|
||||||
|
// patMgr
|
||||||
|
#define WX_PAT_MGR_OFFSET 0x931730
|
||||||
|
// searchContactMgr
|
||||||
|
#define WX_SEARCH_CONTACT_MGR_OFFSET 0xa6cb00
|
||||||
|
// appMsgMgr
|
||||||
|
#define WX_APP_MSG_MGR_OFFSET 0x76ae20
|
||||||
|
// sendMessageMgr
|
||||||
|
#define WX_SEND_MESSAGE_MGR_OFFSET 0x768140
|
||||||
|
|
||||||
|
|
||||||
|
// setChatMsgValue
|
||||||
|
#define WX_INIT_CHAT_MSG_OFFSET 0xf59e40
|
||||||
|
|
||||||
|
// chatMsg
|
||||||
|
#define WX_NEW_CHAT_MSG_OFFSET 0x76f010
|
||||||
|
#define WX_FREE_CHAT_MSG_OFFSET 0x756960
|
||||||
|
#define WX_FREE_CHAT_MSG_2_OFFSET 0x6f4ea0
|
||||||
|
#define WX_FREE_CHAT_MSG_INSTANCE_COUNTER_OFFSET 0x756e30
|
||||||
|
|
||||||
|
|
||||||
|
//sns
|
||||||
|
#define WX_SNS_GET_FIRST_PAGE_OFFSET 0x14e2140
|
||||||
|
#define WX_SNS_GET_NEXT_PAGE_OFFSET 0x14e21e0
|
||||||
|
|
||||||
|
//chat room
|
||||||
|
#define WX_GET_CHAT_ROOM_DETAIL_INFO_OFFSET 0xbde090
|
||||||
|
// chatRoomInfo
|
||||||
|
#define WX_NEW_CHAT_ROOM_INFO_OFFSET 0xe99c40
|
||||||
|
#define WX_FREE_CHAT_ROOM_INFO_OFFSET 0xe99f40
|
||||||
|
#define WX_DEL_CHAT_ROOM_MEMBER_OFFSET 0xbd22a0
|
||||||
|
#define WX_ADD_MEMBER_TO_CHAT_ROOM_OFFSET 0xbd1dc0
|
||||||
|
|
||||||
|
|
||||||
|
// chatRoom
|
||||||
|
#define WX_INIT_CHAT_ROOM_OFFSET 0xe97890
|
||||||
|
#define WX_FREE_CHAT_ROOM_OFFSET 0xe97ab0
|
||||||
|
|
||||||
|
#define WX_GET_MEMBER_FROM_CHAT_ROOM_OFFSET 0xbdf260
|
||||||
|
#define WX_MOD_CHAT_ROOM_MEMBER_NICK_NAME_OFFSET 0xbd9680
|
||||||
|
|
||||||
|
#define WX_TOP_MSG_OFFSET 0xbe1840
|
||||||
|
#define WX_REMOVE_TOP_MSG_OFFSET 0xbe1620
|
||||||
|
|
||||||
|
#define WX_GET_MEMBER_NICKNAME_OFFSET 0xbdf3f0
|
||||||
|
|
||||||
|
#define WX_FREE_CONTACT_OFFSET 0xea7880
|
||||||
|
|
||||||
|
// wcpayinfo
|
||||||
|
#define WX_NEW_WCPAYINFO_OFFSET 0x7b2e60
|
||||||
|
#define WX_FREE_WCPAYINFO_OFFSET 0x79c250
|
||||||
|
#define WX_CONFIRM_RECEIPT_OFFSET 0x15e2c20
|
||||||
|
|
||||||
|
|
||||||
|
//contact
|
||||||
|
#define WX_CONTACT_GET_LIST_OFFSET 0xc089f0
|
||||||
|
#define WX_CONTACT_DEL_OFFSET 0xb9b3b0
|
||||||
|
|
||||||
|
#define WX_SET_VALUE_OFFSET 0x1f80900
|
||||||
|
#define WX_DO_DEL_CONTACT_OFFSET 0xca6480
|
||||||
|
#define WX_GET_CONTACT_OFFSET 0xc04e00
|
||||||
|
#define WX_DO_VERIFY_USER_OFFSET 0xc02100
|
||||||
|
#define WX_VERIFY_MSG_OFFSET 0xf59d40
|
||||||
|
#define WX_VERIFY_OK_OFFSET 0xa18bd0
|
||||||
|
#define WX_NEW_ADD_FRIEND_HELPER_OFFSET 0xa17d50
|
||||||
|
#define WX_FREE_ADD_FRIEND_HELPER_OFFSET 0xa17e70
|
||||||
|
|
||||||
|
// pushAttachTask
|
||||||
|
|
||||||
|
|
||||||
|
#define WX_PUSH_ATTACH_TASK_OFFSET 0x82bb40
|
||||||
|
|
||||||
|
#define WX_FREE_CHAT_MSG_OFFSET 0x756960
|
||||||
|
#define WX_GET_MGR_BY_PREFIX_LOCAL_ID_OFFSET 0xbc0370
|
||||||
|
#define WX_GET_CURRENT_DATA_PATH_OFFSET 0xc872c0
|
||||||
|
#define WX_APP_MSG_INFO_OFFSET 0x7b3d20
|
||||||
|
#define WX_GET_APP_MSG_XML_OFFSET 0xe628a0
|
||||||
|
#define WX_FREE_APP_MSG_INFO_OFFSET 0x79d900
|
||||||
|
#define WX_PUSH_THUMB_TASK_OFFSET 0x82ba40
|
||||||
|
#define WX_DOWNLOAD_VIDEO_IMG_OFFSET 0xd46c30
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// pat
|
||||||
|
#define WX_SEND_PAT_MSG_OFFSET 0x1421940
|
||||||
|
#define WX_RET_OFFSET 0x1D58751
|
||||||
|
|
||||||
|
|
||||||
|
//search hook
|
||||||
|
#define WX_SEARCH_CONTACT_ERROR_CODE_HOOK_OFFSET 0xe17054
|
||||||
|
#define WX_SEARCH_CONTACT_ERROR_CODE_HOOK_NEXT_OFFSET 0xf57a20
|
||||||
|
#define WX_SEARCH_CONTACT_DETAIL_HOOK_OFFSET 0xa8ceb0
|
||||||
|
#define WX_SEARCH_CONTACT_DETAIL_HOOK_NEXT_OFFSET 0xa8d100
|
||||||
|
#define WX_SEARCH_CONTACT_OFFSET 0xcd1510
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//login
|
||||||
|
#define WX_LOGOUT_OFFSET 0xe58870
|
||||||
|
#define WX_ACCOUNT_SERVICE_OFFSET 0x768c80
|
||||||
|
#define WX_GET_APP_DATA_SAVE_PATH_OFFSET 0xf3a610
|
||||||
|
#define WX_GET_CURRENT_DATA_PATH_OFFSET 0xc872c0
|
||||||
|
|
||||||
|
|
||||||
|
//forward
|
||||||
|
#define WX_FORWARD_MSG_OFFSET 0xce6730
|
||||||
|
// send file
|
||||||
|
#define WX_SEND_FILE_OFFSET 0xb6d1f0
|
||||||
|
// send image
|
||||||
|
#define WX_SEND_IMAGE_OFFSET 0xce6640
|
||||||
|
// send text
|
||||||
|
#define WX_SEND_TEXT_OFFSET 0xce6c80
|
||||||
|
|
||||||
|
|
||||||
|
//ocr
|
||||||
|
#define WX_INIT_OBJ_OFFSET 0x7a98f0
|
||||||
|
#define WX_OCR_MANAGER_OFFSET 0x7ae470
|
||||||
|
#define WX_DO_OCR_TASK_OFFSET 0x13230c0
|
||||||
|
|
||||||
|
|
||||||
|
//storage
|
||||||
|
|
||||||
|
#define CONTACT_G_PINSTANCE_OFFSET 0x2ffddc8
|
||||||
|
#define DB_MICRO_MSG_OFFSET 0x68
|
||||||
|
#define DB_CHAT_MSG_OFFSET 0x1C0
|
||||||
|
#define DB_MISC_OFFSET 0x3D8
|
||||||
|
#define DB_EMOTION_OFFSET 0x558
|
||||||
|
#define DB_MEDIA_OFFSET 0x9B8
|
||||||
|
#define DB_BIZCHAT_MSG_OFFSET 0x1120
|
||||||
|
#define DB_FUNCTION_MSG_OFFSET 0x11B0
|
||||||
|
#define DB_NAME_OFFSET 0x14
|
||||||
|
|
||||||
|
#define STORAGE_START_OFFSET 0x13f8
|
||||||
|
#define STORAGE_END_OFFSET 0x13fc
|
||||||
|
|
||||||
|
#define PUBLIC_MSG_MGR_OFFSET 0x303df74
|
||||||
|
#define MULTI_DB_MSG_MGR_OFFSET 0x30403b8
|
||||||
|
#define FAVORITE_STORAGE_MGR_OFFSET 0x303fd40
|
||||||
|
#define FTS_FAVORITE_MGR_OFFSET 0x2ffe908
|
||||||
|
|
||||||
|
#define OP_LOG_STORAGE_VFTABLE 0x2AD3A20
|
||||||
|
#define CHAT_MSG_STORAGE_VFTABLE 0x2AC10F0
|
||||||
|
#define CHAT_CR_MSG_STORAGE_VFTABLE 0x2ABEF14
|
||||||
|
#define SESSION_STORAGE_VFTABLE 0x2AD3578
|
||||||
|
#define APP_INFO_STORAGE_VFTABLE 0x2ABCC58
|
||||||
|
#define HEAD_IMG_STORAGE_VFTABLE 0x2ACD9DC
|
||||||
|
#define HEAD_IMG_URL_STORAGE_VFTABLE 0x2ACDF70
|
||||||
|
|
||||||
|
#define BIZ_INFO_STORAGE_VFTABLE 0x2ABD718
|
||||||
|
#define TICKET_INFO_STORAGE_VFTABLE 0x2AD5400
|
||||||
|
#define CHAT_ROOM_STORAGE_VFTABLE 0x2AC299C
|
||||||
|
#define CHAT_ROOM_INFO_STORAGE_VFTABLE 0x2AC245C
|
||||||
|
#define MEDIA_STORAGE_VFTABLE 0x2ACE998
|
||||||
|
#define NAME_2_ID_STORAGE_VFTABLE 0x2AD222C
|
||||||
|
#define EMOTION_PACKAGE_STORAGE_VFTABLE 0x2AC6400
|
||||||
|
|
||||||
|
#define EMOTION_STORAGE_VFTABLE 0x2AC7018
|
||||||
|
#define BUFINFO_STORAGE_VFTABLE 0x2AC3178
|
||||||
|
|
||||||
|
#define CUSTOM_EMOTION_STORAGE_VFTABLE 0x2AC4E90
|
||||||
|
#define DEL_SESSIONINFO_STORAGE_VFTABLE 0x2AC5F98
|
||||||
|
#define FUNCTION_MSG_STORAGE_VFTABLE 0x2ACD10C
|
||||||
|
|
||||||
|
#define FUNCTION_MSG_TASK_STORAGE_VFTABLE 0x2ACC5C8
|
||||||
|
#define REVOKE_MSG_STORAGE_VFTABLE 0x2AD27BC
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*******************hook*********************************************/
|
||||||
|
|
||||||
|
|
||||||
|
// hook image
|
||||||
|
#define WX_HOOK_IMG_OFFSET 0xd723dc
|
||||||
|
#define WX_HOOK_IMG_NEXT_OFFSET 0xe91d90
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// hook log
|
||||||
|
#define WX_HOOK_LOG_OFFSET 0xf57d67
|
||||||
|
#define WX_HOOK_LOG_NEXT_OFFSET 0x240ea71
|
||||||
|
|
||||||
|
// hook msg
|
||||||
|
|
||||||
|
#define WX_RECV_MSG_HOOK_OFFSET 0xd19a0b
|
||||||
|
#define WX_RECV_MSG_HOOK_NEXT_OFFSET 0x756960
|
||||||
|
#define WX_SNS_HOOK_OFFSET 0x14f9e15
|
||||||
|
#define WX_SNS_HOOK_NEXT_OFFSET 0x14fa0a0
|
||||||
|
|
||||||
|
|
||||||
|
// hook voice
|
||||||
|
#define WX_HOOK_VOICE_OFFSET 0xd4d8d8
|
||||||
|
#define WX_HOOK_VOICE_NEXT_OFFSET 0x203d130
|
||||||
|
#define WX_SELF_ID_OFFSET 0x2FFD484
|
||||||
|
|
||||||
|
/*******************hook end*********************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/***************************sqlite3***************************************/
|
||||||
|
#define SQLITE_OK 0 /* Successful result */
|
||||||
|
/* beginning-of-error-codes */
|
||||||
|
#define SQLITE_ERROR 1 /* Generic error */
|
||||||
|
#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
|
||||||
|
#define SQLITE_PERM 3 /* Access permission denied */
|
||||||
|
#define SQLITE_ABORT 4 /* Callback routine requested an abort */
|
||||||
|
#define SQLITE_BUSY 5 /* The database file is locked */
|
||||||
|
#define SQLITE_LOCKED 6 /* A table in the database is locked */
|
||||||
|
#define SQLITE_NOMEM 7 /* A malloc() failed */
|
||||||
|
#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
|
||||||
|
#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
|
||||||
|
#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
|
||||||
|
#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
|
||||||
|
#define SQLITE_NOTFOUND 12 /* Unknown opcode in sqlite3_file_control() */
|
||||||
|
#define SQLITE_FULL 13 /* Insertion failed because database is full */
|
||||||
|
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
|
||||||
|
#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
|
||||||
|
#define SQLITE_EMPTY 16 /* Internal use only */
|
||||||
|
#define SQLITE_SCHEMA 17 /* The database schema changed */
|
||||||
|
#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
|
||||||
|
#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
|
||||||
|
#define SQLITE_MISMATCH 20 /* Data type mismatch */
|
||||||
|
#define SQLITE_MISUSE 21 /* Library used incorrectly */
|
||||||
|
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
|
||||||
|
#define SQLITE_AUTH 23 /* Authorization denied */
|
||||||
|
#define SQLITE_FORMAT 24 /* Not used */
|
||||||
|
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
|
||||||
|
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
|
||||||
|
#define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */
|
||||||
|
#define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */
|
||||||
|
#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
|
||||||
|
#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
|
||||||
|
/* end-of-error-codes */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI3REF: Extended Result Codes
|
||||||
|
** KEYWORDS: {extended result code definitions}
|
||||||
|
**
|
||||||
|
** In its default configuration, SQLite API routines return one of 30 integer
|
||||||
|
** [result codes]. However, experience has shown that many of
|
||||||
|
** these result codes are too coarse-grained. They do not provide as
|
||||||
|
** much information about problems as programmers might like. In an effort to
|
||||||
|
** address this, newer versions of SQLite (version 3.3.8 [dateof:3.3.8]
|
||||||
|
** and later) include
|
||||||
|
** support for additional result codes that provide more detailed information
|
||||||
|
** about errors. These [extended result codes] are enabled or disabled
|
||||||
|
** on a per database connection basis using the
|
||||||
|
** [sqlite3_extended_result_codes()] API. Or, the extended code for
|
||||||
|
** the most recent error can be obtained using
|
||||||
|
** [sqlite3_extended_errcode()].
|
||||||
|
*/
|
||||||
|
#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1 << 8))
|
||||||
|
#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2 << 8))
|
||||||
|
#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3 << 8))
|
||||||
|
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1 << 8))
|
||||||
|
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2 << 8))
|
||||||
|
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3 << 8))
|
||||||
|
#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4 << 8))
|
||||||
|
#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5 << 8))
|
||||||
|
#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6 << 8))
|
||||||
|
#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7 << 8))
|
||||||
|
#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8 << 8))
|
||||||
|
#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9 << 8))
|
||||||
|
#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10 << 8))
|
||||||
|
#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11 << 8))
|
||||||
|
#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12 << 8))
|
||||||
|
#define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13 << 8))
|
||||||
|
#define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14 << 8))
|
||||||
|
#define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15 << 8))
|
||||||
|
#define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16 << 8))
|
||||||
|
#define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17 << 8))
|
||||||
|
#define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18 << 8))
|
||||||
|
#define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19 << 8))
|
||||||
|
#define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20 << 8))
|
||||||
|
#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21 << 8))
|
||||||
|
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22 << 8))
|
||||||
|
#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23 << 8))
|
||||||
|
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24 << 8))
|
||||||
|
#define SQLITE_IOERR_GETTEMPPATH (SQLITE_IOERR | (25 << 8))
|
||||||
|
#define SQLITE_IOERR_CONVPATH (SQLITE_IOERR | (26 << 8))
|
||||||
|
#define SQLITE_IOERR_VNODE (SQLITE_IOERR | (27 << 8))
|
||||||
|
#define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28 << 8))
|
||||||
|
#define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29 << 8))
|
||||||
|
#define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30 << 8))
|
||||||
|
#define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31 << 8))
|
||||||
|
#define SQLITE_IOERR_DATA (SQLITE_IOERR | (32 << 8))
|
||||||
|
#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33 << 8))
|
||||||
|
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1 << 8))
|
||||||
|
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2 << 8))
|
||||||
|
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1 << 8))
|
||||||
|
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2 << 8))
|
||||||
|
#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4 << 8))
|
||||||
|
#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5 << 8)) /* Not Used */
|
||||||
|
#define SQLITE_CANTOPEN_SYMLINK (SQLITE_CANTOPEN | (6 << 8))
|
||||||
|
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1 << 8))
|
||||||
|
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2 << 8))
|
||||||
|
#define SQLITE_CORRUPT_INDEX (SQLITE_CORRUPT | (3 << 8))
|
||||||
|
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1 << 8))
|
||||||
|
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2 << 8))
|
||||||
|
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3 << 8))
|
||||||
|
#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4 << 8))
|
||||||
|
#define SQLITE_READONLY_CANTINIT (SQLITE_READONLY | (5 << 8))
|
||||||
|
#define SQLITE_READONLY_DIRECTORY (SQLITE_READONLY | (6 << 8))
|
||||||
|
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_FOREIGNKEY (SQLITE_CONSTRAINT | (3 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_FUNCTION (SQLITE_CONSTRAINT | (4 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_NOTNULL (SQLITE_CONSTRAINT | (5 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_PRIMARYKEY (SQLITE_CONSTRAINT | (6 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT | (10 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT | (11 << 8))
|
||||||
|
#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT | (12 << 8))
|
||||||
|
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1 << 8))
|
||||||
|
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2 << 8))
|
||||||
|
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1 << 8))
|
||||||
|
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1 << 8))
|
||||||
|
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1 << 8))
|
||||||
|
#define SQLITE_OK_SYMLINK (SQLITE_OK | (2 << 8)) /* internal use only */
|
||||||
|
|
||||||
|
|
||||||
|
#define SQLITE_INTEGER 1
|
||||||
|
#define SQLITE_FLOAT 2
|
||||||
|
#define SQLITE_BLOB 4
|
||||||
|
#define SQLITE_NULL 5
|
||||||
|
#define SQLITE_TEXT 3
|
||||||
|
|
||||||
|
#define SQLITE3_EXEC_OFFSET 0x1e24f70
|
||||||
|
#define SQLITE3_BACKUP_INIT_OFFSET 0x1dea900
|
||||||
|
#define SQLITE3_PREPARE_OFFSET 0x1e2b8c0
|
||||||
|
#define SQLITE3_OPEN_OFFSET 0x1e598b0
|
||||||
|
#define SQLITE3_BACKUP_STEP_OFFSET 0x1dead00
|
||||||
|
#define SQLITE3_BACKUP_REMAINING_OFFSET 0x1deb440
|
||||||
|
#define SQLITE3_BACKUP_PAGECOUNT_OFFSET 0x1deb450
|
||||||
|
#define SQLITE3_BACKUP_FINISH_OFFSET 0x1deb340
|
||||||
|
#define SQLITE3_SLEEP_OFFSET 0x1e5a0f0
|
||||||
|
#define SQLITE3_ERRCODE_OFFSET 0x1e58550
|
||||||
|
#define SQLITE3_CLOSE_OFFSET 0x1e56cd0
|
||||||
|
#define SQLITE3_STEP_OFFSET 0x1df3770
|
||||||
|
#define SQLITE3_COLUMN_COUNT_OFFSET 0x1df3c80
|
||||||
|
#define SQLITE3_COLUMN_NAME_OFFSET 0x1df4570
|
||||||
|
#define SQLITE3_COLUMN_TYPE_OFFSET 0x1df4410
|
||||||
|
#define SQLITE3_COLUMN_BLOB_OFFSET 0x1df3cc0
|
||||||
|
#define SQLITE3_COLUMN_BYTES_OFFSET 0x1df3da0
|
||||||
|
#define SQLITE3_FINALIZE_OFFSET 0x1df2740
|
||||||
|
|
||||||
|
typedef int (*Sqlite3_callback)(void*, int, char**, char**);
|
||||||
|
|
||||||
|
typedef int(__cdecl* Sqlite3_exec)(DWORD, /* An open database */
|
||||||
|
const char* sql, /* SQL to be evaluated */
|
||||||
|
Sqlite3_callback, /* Callback function */
|
||||||
|
void*, /* 1st argument to callback */
|
||||||
|
char** errmsg /* Error msg written here */
|
||||||
|
);
|
||||||
|
typedef DWORD(__cdecl* Sqlite3_backup_init)(
|
||||||
|
DWORD* pDest, /* Destination database handle */
|
||||||
|
const char* zDestName, /* Destination database name */
|
||||||
|
DWORD* pSource, /* Source database handle */
|
||||||
|
const char* zSourceName /* Source database name */
|
||||||
|
);
|
||||||
|
typedef int(__cdecl* Sqlite3_prepare)(
|
||||||
|
DWORD db, /* Database handle */
|
||||||
|
const char* zSql, /* SQL statement, UTF-8 encoded */
|
||||||
|
int nByte, /* Maximum length of zSql in bytes. */
|
||||||
|
DWORD** ppStmt, /* OUT: Statement handle */
|
||||||
|
const char** pzTail /* OUT: Pointer to unused portion of zSql */
|
||||||
|
);
|
||||||
|
typedef int(__cdecl* Sqlite3_open)(const char* filename, DWORD** ppDb);
|
||||||
|
typedef int(__cdecl* Sqlite3_backup_step)(DWORD* p, int nPage);
|
||||||
|
typedef int(__cdecl* Sqlite3_backup_remaining)(DWORD* p);
|
||||||
|
typedef int(__cdecl* Sqlite3_backup_pagecount)(DWORD* p);
|
||||||
|
typedef int(__cdecl* Sqlite3_backup_finish)(DWORD* p);
|
||||||
|
typedef int(__cdecl* Sqlite3_sleep)(int);
|
||||||
|
typedef int(__cdecl* Sqlite3_errcode)(DWORD* db);
|
||||||
|
typedef int(__cdecl* Sqlite3_close)(DWORD*);
|
||||||
|
|
||||||
|
typedef int(__cdecl* Sqlite3_step)(DWORD*);
|
||||||
|
typedef int(__cdecl* Sqlite3_column_count)(DWORD* pStmt);
|
||||||
|
typedef const char*(__cdecl* Sqlite3_column_name)(DWORD*, int N);
|
||||||
|
typedef int(__cdecl* Sqlite3_column_type)(DWORD*, int iCol);
|
||||||
|
typedef const void*(__cdecl* Sqlite3_column_blob)(DWORD*, int iCol);
|
||||||
|
typedef int(__cdecl* Sqlite3_column_bytes)(DWORD*, int iCol);
|
||||||
|
typedef int(__cdecl* Sqlite3_finalize)(DWORD* pStmt);
|
||||||
|
|
||||||
|
|
||||||
|
/***************************sqlite3 end*************************************/
|
||||||
|
|
||||||
|
struct SqlResult {
|
||||||
|
char *column_name;
|
||||||
|
DWORD column_name_len;
|
||||||
|
char *content;
|
||||||
|
DWORD content_len;
|
||||||
|
BOOL is_blob;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WeChatString {
|
||||||
|
wchar_t *ptr;
|
||||||
|
DWORD length;
|
||||||
|
DWORD max_length;
|
||||||
|
DWORD c_ptr = 0;
|
||||||
|
DWORD c_len = 0;
|
||||||
|
WeChatString() { WeChatString(NULL); }
|
||||||
|
|
||||||
|
WeChatString(std::wstring &s) {
|
||||||
|
ptr = (wchar_t *)(s.c_str());
|
||||||
|
length = s.length();
|
||||||
|
max_length = s.length() * 2;
|
||||||
|
}
|
||||||
|
WeChatString(const wchar_t *pStr) { WeChatString((wchar_t *)pStr); }
|
||||||
|
WeChatString(int tmp) {
|
||||||
|
ptr = NULL;
|
||||||
|
length = 0x0;
|
||||||
|
max_length = 0x0;
|
||||||
|
}
|
||||||
|
WeChatString(wchar_t *pStr) {
|
||||||
|
ptr = pStr;
|
||||||
|
length = wcslen(pStr);
|
||||||
|
max_length = wcslen(pStr) * 2;
|
||||||
|
}
|
||||||
|
void set_value(const wchar_t *pStr) {
|
||||||
|
ptr = (wchar_t *)pStr;
|
||||||
|
length = wcslen(pStr);
|
||||||
|
max_length = wcslen(pStr) * 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct SelfInfoInner{
|
||||||
|
std::string name;
|
||||||
|
std::string city;
|
||||||
|
std::string province;
|
||||||
|
std::string country;
|
||||||
|
std::string account;
|
||||||
|
std::string wxid;
|
||||||
|
std::string mobile;
|
||||||
|
std::string head_img;
|
||||||
|
std::string data_save_path;
|
||||||
|
std::string signature;
|
||||||
|
std::string current_data_path;
|
||||||
|
std::string db_key;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VectorInner {
|
||||||
|
#ifdef _DEBUG
|
||||||
|
DWORD head;
|
||||||
|
#endif
|
||||||
|
DWORD start;
|
||||||
|
DWORD finsh;
|
||||||
|
DWORD end;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TableInfo {
|
||||||
|
char *name;
|
||||||
|
DWORD name_len;
|
||||||
|
char *table_name;
|
||||||
|
DWORD table_name_len;
|
||||||
|
char *sql;
|
||||||
|
DWORD sql_len;
|
||||||
|
char *rootpage;
|
||||||
|
DWORD rootpage_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DatabaseInfo {
|
||||||
|
DWORD handle = 0;
|
||||||
|
wchar_t *db_name = NULL;
|
||||||
|
DWORD db_name_len = 0;
|
||||||
|
std::vector<TableInfo> tables;
|
||||||
|
DWORD count = 0;
|
||||||
|
DWORD extrainfo = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Contact {
|
||||||
|
WeChatString wxid;
|
||||||
|
WeChatString custom_account;
|
||||||
|
WeChatString encrypt_name;
|
||||||
|
WeChatString nick_name;
|
||||||
|
WeChatString pinyin;
|
||||||
|
WeChatString pinyin_all;
|
||||||
|
int del_flag;
|
||||||
|
int type;
|
||||||
|
int verify_flag;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChatRoomInfo {
|
||||||
|
DWORD vftable;
|
||||||
|
WeChatString chat_room_id;
|
||||||
|
WeChatString notice;
|
||||||
|
WeChatString admin;
|
||||||
|
DWORD filed_40;
|
||||||
|
DWORD filed_44;
|
||||||
|
DWORD filed_48;
|
||||||
|
DWORD filed_4C;
|
||||||
|
WeChatString xml;
|
||||||
|
DWORD filed_64;
|
||||||
|
DWORD filed_68;
|
||||||
|
DWORD filed_6C;
|
||||||
|
DWORD filed_70;
|
||||||
|
DWORD filed_74;
|
||||||
|
DWORD filed_78;
|
||||||
|
DWORD filed_7C;
|
||||||
|
DWORD filed_80;
|
||||||
|
DWORD filed_84;
|
||||||
|
DWORD filed_88;
|
||||||
|
DWORD filed_8c;
|
||||||
|
DWORD filed_90;
|
||||||
|
DWORD filed_94;
|
||||||
|
DWORD filed_98;
|
||||||
|
DWORD filed_9C;
|
||||||
|
DWORD filed_A0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChatRoomInfoInner {
|
||||||
|
WeChatString chat_room_id;
|
||||||
|
WeChatString notice;
|
||||||
|
WeChatString admin;
|
||||||
|
WeChatString xml;
|
||||||
|
|
||||||
|
~ChatRoomInfoInner(){
|
||||||
|
if(chat_room_id.ptr){
|
||||||
|
delete []chat_room_id.ptr;
|
||||||
|
chat_room_id.ptr = nullptr;
|
||||||
|
}
|
||||||
|
if(notice.ptr){
|
||||||
|
delete []notice.ptr;
|
||||||
|
notice.ptr = nullptr;
|
||||||
|
}
|
||||||
|
if(admin.ptr){
|
||||||
|
delete []admin.ptr;
|
||||||
|
admin.ptr = nullptr;
|
||||||
|
}
|
||||||
|
if(xml.ptr){
|
||||||
|
delete []xml.ptr;
|
||||||
|
xml.ptr = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChatRoomInner{
|
||||||
|
char* members;
|
||||||
|
wchar_t* chat_room;
|
||||||
|
wchar_t* admin;
|
||||||
|
~ChatRoomInner(){
|
||||||
|
delete []members;
|
||||||
|
delete []chat_room;
|
||||||
|
delete []admin;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UserInfo {
|
||||||
|
int error_code;
|
||||||
|
wchar_t *keyword;
|
||||||
|
int keyword_len;
|
||||||
|
wchar_t *v3;
|
||||||
|
int v3_len;
|
||||||
|
wchar_t *nickname;
|
||||||
|
int nickname_len;
|
||||||
|
wchar_t *signature;
|
||||||
|
int signature_len;
|
||||||
|
wchar_t *v2;
|
||||||
|
int v2_len;
|
||||||
|
wchar_t *nation;
|
||||||
|
int nation_len;
|
||||||
|
wchar_t *province;
|
||||||
|
int province_len;
|
||||||
|
wchar_t *city;
|
||||||
|
int city_len;
|
||||||
|
wchar_t *big_image;
|
||||||
|
int big_image_len;
|
||||||
|
wchar_t *small_image;
|
||||||
|
int small_image_len;
|
||||||
|
DWORD sex;
|
||||||
|
BOOL over;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AtInner{
|
||||||
|
DWORD start;
|
||||||
|
DWORD finsh;
|
||||||
|
DWORD end;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChatMsg {
|
||||||
|
DWORD **field0_0x0;
|
||||||
|
DWORD field1_0x4;
|
||||||
|
ULONG64 sequence;
|
||||||
|
DWORD field3_0x10;
|
||||||
|
DWORD field4_0x14;
|
||||||
|
ULONG64 msgSequence;
|
||||||
|
DWORD localId;
|
||||||
|
DWORD field7_0x24;
|
||||||
|
DWORD field8_0x28;
|
||||||
|
DWORD field9_0x2c;
|
||||||
|
ULONG64 msgId;
|
||||||
|
DWORD type;
|
||||||
|
DWORD isSendMsg;
|
||||||
|
DWORD msgStatus;
|
||||||
|
DWORD timestamp;
|
||||||
|
WeChatString talker;
|
||||||
|
DWORD field16_0x5c;
|
||||||
|
DWORD field17_0x60;
|
||||||
|
DWORD field18_0x64;
|
||||||
|
DWORD field19_0x68;
|
||||||
|
DWORD field20_0x6c;
|
||||||
|
WeChatString content;
|
||||||
|
DWORD field22_0x84;
|
||||||
|
DWORD field23_0x88;
|
||||||
|
DWORD field24_0x8c;
|
||||||
|
DWORD field25_0x90;
|
||||||
|
DWORD field26_0x94;
|
||||||
|
DWORD field27_0x98;
|
||||||
|
DWORD field28_0x9c;
|
||||||
|
DWORD field29_0xa0;
|
||||||
|
DWORD field30_0xa4;
|
||||||
|
DWORD field31_0xa8;
|
||||||
|
DWORD field32_0xac;
|
||||||
|
DWORD field33_0xb0;
|
||||||
|
DWORD field34_0xb4;
|
||||||
|
DWORD field35_0xb8;
|
||||||
|
DWORD field36_0xbc;
|
||||||
|
DWORD field37_0xc0;
|
||||||
|
DWORD field38_0xc4;
|
||||||
|
DWORD field39_0xc8;
|
||||||
|
DWORD field40_0xcc;
|
||||||
|
DWORD field41_0xd0;
|
||||||
|
DWORD field42_0xd4;
|
||||||
|
DWORD field43_0xd8;
|
||||||
|
DWORD field44_0xdc;
|
||||||
|
DWORD field45_0xe0;
|
||||||
|
DWORD field46_0xe4;
|
||||||
|
DWORD field47_0xe8;
|
||||||
|
DWORD field48_0xec;
|
||||||
|
DWORD field49_0xf0;
|
||||||
|
DWORD field50_0xf4;
|
||||||
|
DWORD field51_0xf8;
|
||||||
|
DWORD field52_0xfc;
|
||||||
|
DWORD field53_0x100;
|
||||||
|
DWORD field54_0x104;
|
||||||
|
DWORD field55_0x108;
|
||||||
|
DWORD field56_0x10c;
|
||||||
|
DWORD field57_0x110;
|
||||||
|
DWORD field58_0x114;
|
||||||
|
DWORD field59_0x118;
|
||||||
|
DWORD field60_0x11c;
|
||||||
|
DWORD field61_0x120;
|
||||||
|
DWORD field62_0x124;
|
||||||
|
DWORD field63_0x128;
|
||||||
|
DWORD field64_0x12c;
|
||||||
|
DWORD field65_0x130;
|
||||||
|
DWORD field66_0x134;
|
||||||
|
DWORD field67_0x138;
|
||||||
|
DWORD field68_0x13c;
|
||||||
|
DWORD field69_0x140;
|
||||||
|
DWORD field70_0x144;
|
||||||
|
DWORD field71_0x148;
|
||||||
|
DWORD field72_0x14c;
|
||||||
|
DWORD field73_0x150;
|
||||||
|
DWORD field74_0x154;
|
||||||
|
DWORD field75_0x158;
|
||||||
|
DWORD field76_0x15c;
|
||||||
|
DWORD field77_0x160;
|
||||||
|
DWORD field78_0x164;
|
||||||
|
DWORD field79_0x168;
|
||||||
|
DWORD field80_0x16c;
|
||||||
|
DWORD field81_0x170;
|
||||||
|
WeChatString fromGroup;
|
||||||
|
WeChatString sign;
|
||||||
|
WeChatString thumbPath;
|
||||||
|
WeChatString path;
|
||||||
|
DWORD field86_0x1c4;
|
||||||
|
DWORD field87_0x1c8;
|
||||||
|
DWORD field88_0x1cc;
|
||||||
|
DWORD field89_0x1d0;
|
||||||
|
DWORD field90_0x1d4;
|
||||||
|
DWORD field91_0x1d8;
|
||||||
|
DWORD field92_0x1dc;
|
||||||
|
DWORD field93_0x1e0;
|
||||||
|
DWORD field94_0x1e4;
|
||||||
|
DWORD field95_0x1e8;
|
||||||
|
DWORD field96_0x1ec;
|
||||||
|
WeChatString signature;
|
||||||
|
DWORD field98_0x204;
|
||||||
|
DWORD field99_0x208;
|
||||||
|
DWORD field100_0x20c;
|
||||||
|
DWORD field101_0x210;
|
||||||
|
DWORD field102_0x214;
|
||||||
|
DWORD field103_0x218;
|
||||||
|
DWORD field104_0x21c;
|
||||||
|
DWORD field105_0x220;
|
||||||
|
DWORD field106_0x224;
|
||||||
|
DWORD field107_0x228;
|
||||||
|
DWORD field108_0x22c;
|
||||||
|
DWORD field109_0x230;
|
||||||
|
DWORD field110_0x234;
|
||||||
|
DWORD field111_0x238;
|
||||||
|
DWORD field112_0x23c;
|
||||||
|
DWORD field113_0x240;
|
||||||
|
DWORD field114_0x244;
|
||||||
|
DWORD field115_0x248;
|
||||||
|
DWORD field116_0x24c;
|
||||||
|
DWORD field117_0x250;
|
||||||
|
DWORD field118_0x254;
|
||||||
|
DWORD field119_0x258;
|
||||||
|
DWORD field120_0x25c;
|
||||||
|
DWORD field121_0x260;
|
||||||
|
DWORD field122_0x264;
|
||||||
|
DWORD field123_0x268;
|
||||||
|
DWORD field124_0x26c;
|
||||||
|
DWORD field125_0x270;
|
||||||
|
DWORD field126_0x274;
|
||||||
|
DWORD field127_0x278;
|
||||||
|
DWORD field128_0x27c;
|
||||||
|
DWORD field129_0x280;
|
||||||
|
DWORD field130_0x284;
|
||||||
|
DWORD field131_0x288;
|
||||||
|
DWORD field132_0x28c;
|
||||||
|
DWORD field133_0x290;
|
||||||
|
DWORD field134_0x294;
|
||||||
|
DWORD field135_0x298;
|
||||||
|
DWORD field136_0x29c;
|
||||||
|
DWORD field137_0x2a0;
|
||||||
|
DWORD field138_0x2a4;
|
||||||
|
DWORD field139_0x2a8;
|
||||||
|
DWORD field140_0x2ac;
|
||||||
|
DWORD field141_0x2b0;
|
||||||
|
int field142_0x2b4;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InnerMessageStruct {
|
||||||
|
char *buffer;
|
||||||
|
int length;
|
||||||
|
~InnerMessageStruct() {
|
||||||
|
if (this->buffer != NULL) {
|
||||||
|
delete[] this->buffer;
|
||||||
|
this->buffer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Unkown{
|
||||||
|
DWORD field1 = 0;
|
||||||
|
DWORD field2= 0;
|
||||||
|
DWORD field3= 0;
|
||||||
|
DWORD field4= 0;
|
||||||
|
DWORD field5= 0;
|
||||||
|
DWORD field6= 0;
|
||||||
|
};
|
||||||
|
#endif
|
BIN
tool/injector/injector.dll
Normal file
BIN
tool/injector/injector.dll
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user