From ba1cf0b97268ea4c92ccb76e568448044f2d3d77 Mon Sep 17 00:00:00 2001 From: Eduardo Alonso Date: Sat, 13 Oct 2018 18:34:55 +0200 Subject: [PATCH] Add cache support for Windows & general refactoring --- G-WinMem/G-WinMem/G-WinMem.cpp | Bin 15794 -> 10174 bytes G-WinMem/G-WinMem/G-WinMem.vcxproj | 9 +- G-WinMem/G-WinMem/G-WinMem.vcxproj.filters | 12 + G-WinMem/G-WinMem/Process.cpp | 263 ++++++++++++++++++ G-WinMem/G-WinMem/Process.h | 40 +++ G-WinMem/G-WinMem/ctpl_stl.h | 256 +++++++++++++++++ .../windows/WindowsHabboClient.java | 50 +++- 7 files changed, 622 insertions(+), 8 deletions(-) create mode 100644 G-WinMem/G-WinMem/Process.cpp create mode 100644 G-WinMem/G-WinMem/Process.h create mode 100644 G-WinMem/G-WinMem/ctpl_stl.h diff --git a/G-WinMem/G-WinMem/G-WinMem.cpp b/G-WinMem/G-WinMem/G-WinMem.cpp index 826e0b0f72ff32f991064a3eaa16c184019d34b5..52b1e103a3509a1d3e0f7e22c9f8ea4acadbba79 100644 GIT binary patch delta 1072 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 I%NeouUkz2mjQ{`u diff --git a/G-WinMem/G-WinMem/G-WinMem.vcxproj b/G-WinMem/G-WinMem/G-WinMem.vcxproj index 6285c9b..58e6a36 100644 --- a/G-WinMem/G-WinMem/G-WinMem.vcxproj +++ b/G-WinMem/G-WinMem/G-WinMem.vcxproj @@ -98,7 +98,7 @@ - Use + NotUsing Level3 Disabled true @@ -148,11 +148,15 @@ + + + + Create Create @@ -161,6 +165,5 @@ - - + \ No newline at end of file diff --git a/G-WinMem/G-WinMem/G-WinMem.vcxproj.filters b/G-WinMem/G-WinMem/G-WinMem.vcxproj.filters index 65bd3c3..ebe7bb6 100644 --- a/G-WinMem/G-WinMem/G-WinMem.vcxproj.filters +++ b/G-WinMem/G-WinMem/G-WinMem.vcxproj.filters @@ -21,6 +21,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + @@ -29,5 +38,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/G-WinMem/G-WinMem/Process.cpp b/G-WinMem/G-WinMem/Process.cpp new file mode 100644 index 0000000..e8046d4 --- /dev/null +++ b/G-WinMem/G-WinMem/Process.cpp @@ -0,0 +1,263 @@ + +#include "ctpl_stl.h" +#include "Process.h" + +#include +#include + +Process::Process() : Process(0) +{} + +Process::Process(int pid) + : mPid(pid), + mHandle(nullptr) +{} + +bool Process::Open() +{ + mHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_OPERATION, false, mPid); + + return true; +} + +std::vector Process::GetChunks() +{ + return mChunks; +} + +void Process::Close() +{ + CloseHandle(mHandle); +} + +void Process::PrintCachedResults(std::vector cache) +{ + const auto offset = 4; + static std::mutex m; + Open(); + + for (auto addr : cache) { + u_char rawMem[1024] = { 0 }; + + if (!ReadProcessMemory(mHandle, addr, rawMem, 1024, nullptr)) + { + std::cout << "Failed to read memory at " << addr << std::endl; + return; + } + + for (auto i = 0; i < (1024 - ((256 - 1) * offset)); i += offset) + { + unsigned char wannabeRC4data[1024] = { 0 }; + unsigned char data[256] = { 0 }; + memcpy(wannabeRC4data, rawMem + i, 1024); + + auto isvalid = true; + + for (auto j = 0; j < 1024; j++) + { + if (j % 4 != 0 && wannabeRC4data[j] != 0) + { + isvalid = false; + break; + } + if (j % 4 == 0) + { + data[j / 4] = wannabeRC4data[j]; + } + } + if (isvalid) + { + m.lock(); + for (auto idx : data) + printf("%02X", static_cast(idx) & 0xFF); + + std::cout << std::endl; + m.unlock(); + } + } + } + Close(); +} + +void Process::PrintRC4Possibilities() +{ + SYSTEM_INFO sys_info; + + static std::mutex m; + + GetSystemInfo(&sys_info); + + Open(); + + FindMaps(sys_info); + + const auto offset = 4; + + CreateMapsForRC4(); + + for (auto k = 0; k < mRC4Maps.size(); k++) + { + auto mem = mRC4Maps[k]; + + if (mem->mSize >= 1024 && mem->mSize <= 1024 + 2 * offset) + { + for (auto i = 0; i < (mem->mSize - ((256 - 1) * offset)); i += offset) + { + unsigned char wannabeRC4data[1024] = { 0 }; + unsigned char data[256] = { 0 }; + memcpy(wannabeRC4data, static_cast(mem->mStart) + i, 1024); + + auto isvalid = true; + + for (auto j = 0; j < 1024; j++) + { + if (j % 4 != 0 && wannabeRC4data[j] != 0) + { + isvalid = false; + break; + } + if (j % 4 == 0) + { + data[j / 4] = wannabeRC4data[j]; + } + } + if (isvalid) + { + m.lock(); + printf("%llx\n",reinterpret_cast(mOutCache[k])); + for (auto idx : data) + printf("%02X", static_cast(idx) & 0xFF); + + std::cout << std::endl; + m.unlock(); + } + } + } + delete mem; + } + Close(); +} + +void Process::CreateMapFromChunk(MemoryChunk *chunk) +{ + const auto offset = 4; + const auto dump = new unsigned char[chunk->mSize + 1]; + + memset(dump, 0, chunk->mSize + 1); + + if (!ReadProcessMemory(mHandle, chunk->mStart, dump, chunk->mSize, nullptr)) + { + std::cout << "Failed to read memory at: " << chunk->mStart << std::endl; + return; + } + + auto maskCount = 0; + int nToMap[256] = { 0 }; + int removeMap[256] = { 0 }; + + for (auto i = 0; i < 256; i++) { + nToMap[i] = -1; + removeMap[i] = -1; + } + + auto matchStart = -1; + auto matchEnd = -1; + + for (auto i = 0; i < chunk->mSize; i += offset) + { + const auto b = (static_cast(dump[i]) + 128) % 256; + const auto indInMap = (i / 4) % 256; + + const auto deletedNumber = removeMap[indInMap]; + + if (deletedNumber != -1) + { + nToMap[deletedNumber] = -1; + maskCount--; + removeMap[indInMap] = -1; + } + + if (nToMap[b] == -1) + { + maskCount++; + removeMap[indInMap] = b; + nToMap[b] = indInMap; + } + else + { + removeMap[nToMap[b]] = -1; + removeMap[indInMap] = b; + nToMap[b] = indInMap; + } + + if (maskCount == 256) + { + if (matchStart == -1) + { + matchStart = i - ((256 - 1) * offset); + matchEnd = i; + } + + if (matchEnd < i - ((256 - 1) * offset)) + { + //printf("maybeValid -> %p\n", static_cast(chunk->mStart) + matchStart); + mOutCache.push_back(static_cast(chunk->mStart) + matchStart); + mRC4Maps.push_back(new MemoryChunk(dump + matchStart, matchEnd - matchStart + 4)); + + matchStart = i - ((256 - 1) * offset); + } + matchEnd = i; + } + } + if (matchStart != -1) + { + mOutCache.push_back(static_cast(chunk->mStart) + matchStart); + mRC4Maps.push_back(new MemoryChunk(dump + matchStart, matchEnd - matchStart + 4)); + } + delete chunk; +} + +void Process::CreateMapsForRC4() +{ + ctpl::thread_pool p(5); + + for (auto chunk : mChunks) { + p.push(std::bind(&Process::CreateMapFromChunk, this, chunk)); + } + + p.stop(true); +} + + + +void Process::FindMaps(SYSTEM_INFO sys_info) +{ + + auto addr = reinterpret_cast(sys_info.lpMinimumApplicationAddress); + const auto end = reinterpret_cast(sys_info.lpMaximumApplicationAddress); + + MEMORY_BASIC_INFORMATION mbi; + + while (addr < end) { + if (!VirtualQueryEx(mHandle, reinterpret_cast(addr), &mbi, sizeof(mbi))) { + std::cout << "Failed to get memory maps\n"; + return; + } + + if (mbi.State == MEM_COMMIT && ((mbi.Protect & PAGE_GUARD) == 0) && ((mbi.Protect & PAGE_NOACCESS) == 0)) { + mChunks.push_back(new MemoryChunk(reinterpret_cast(addr), mbi.RegionSize)); + } + addr += mbi.RegionSize; + } +} + + + +Process::~Process() +{ + for (auto m : mChunks) + delete m; + + for (auto m : mRC4Maps) + delete m; +} diff --git a/G-WinMem/G-WinMem/Process.h b/G-WinMem/G-WinMem/Process.h new file mode 100644 index 0000000..a12ff06 --- /dev/null +++ b/G-WinMem/G-WinMem/Process.h @@ -0,0 +1,40 @@ +#pragma once +#include +#include + +class MemoryChunk +{ +public: + MemoryChunk(LPVOID start, SIZE_T size); + LPVOID mStart; + SIZE_T mSize; +}; + +inline MemoryChunk::MemoryChunk(LPVOID start, SIZE_T size) : + mStart(start), + mSize(size) +{} + + +class Process +{ +public: + Process(); + Process(int pid); + bool Open(); + void Close(); + void FindMaps(SYSTEM_INFO sys_info); + void CreateMapsForRC4(); + void CreateMapFromChunk(MemoryChunk *chunk); + void PrintRC4Possibilities(); + void PrintCachedResults(std::vector cache); + ~Process(); + std::vector GetChunks(); +private: + int mPid; + HANDLE mHandle; + std::vector mChunks; + std::vector mRC4Maps; + std::vector mOutCache; +}; + diff --git a/G-WinMem/G-WinMem/ctpl_stl.h b/G-WinMem/G-WinMem/ctpl_stl.h new file mode 100644 index 0000000..9b59bcd --- /dev/null +++ b/G-WinMem/G-WinMem/ctpl_stl.h @@ -0,0 +1,256 @@ +/********************************************************* +* +* Copyright (C) 2014 by Vitaliy Vitsentiy +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +* +*********************************************************/ + + +#ifndef __ctpl_stl_thread_pool_H__ +#define __ctpl_stl_thread_pool_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +// thread pool to run user's functors with signature +// ret func(int id, other_params) +// where id is the index of the thread that runs the functor +// ret is some return type + + +namespace ctpl { + + namespace detail { + template + class Queue { + public: + bool push(T const & value) { + std::unique_lock lock(this->mutex); + this->q.push(value); + return true; + } + // deletes the retrieved element, do not use for non integral types + bool pop(T & v) { + std::unique_lock lock(this->mutex); + if (this->q.empty()) + return false; + v = this->q.front(); + this->q.pop(); + return true; + } + bool empty() { + std::unique_lock lock(this->mutex); + return this->q.empty(); + } + private: + std::queue q; + std::mutex mutex; + }; + } + + class thread_pool { + + public: + + thread_pool() { this->init(); } + thread_pool(int nThreads) { this->init(); this->resize(nThreads); } + + // the destructor waits for all the functions in the queue to be finished + ~thread_pool() { + this->stop(true); + } + + // get the number of running threads in the pool + int size() { return static_cast(this->threads.size()); } + + // number of idle threads + int n_idle() { return this->nWaiting; } + int n_pending() { return this->nPending; } + std::thread & get_thread(int i) { return *this->threads[i]; } + + // change the number of threads in the pool + // should be called from one thread, otherwise be careful to not interleave, also with this->stop() + // nThreads must be >= 0 + void resize(int nThreads) { + if (!this->isStop && !this->isDone) { + int oldNThreads = static_cast(this->threads.size()); + if (oldNThreads <= nThreads) { // if the number of threads is increased + this->threads.resize(nThreads); + this->flags.resize(nThreads); + + for (int i = oldNThreads; i < nThreads; ++i) { + this->flags[i] = std::make_shared>(false); + this->set_thread(i); + } + } + else { // the number of threads is decreased + for (int i = oldNThreads - 1; i >= nThreads; --i) { + *this->flags[i] = true; // this thread will finish + this->threads[i]->detach(); + } + { + // stop the detached threads that were waiting + std::unique_lock lock(this->mutex); + this->cv.notify_all(); + } + this->threads.resize(nThreads); // safe to delete because the threads are detached + this->flags.resize(nThreads); // safe to delete because the threads have copies of shared_ptr of the flags, not originals + } + } + } + + // empty the queue + void clear_queue() { + std::function * _f; + while (this->q.pop(_f)) + delete _f; // empty the queue + } + + // pops a functional wrapper to the original function + std::function pop() { + std::function * _f = nullptr; + this->q.pop(_f); + std::unique_ptr> func(_f); // at return, delete the function even if an exception occurred + std::function f; + if (_f) + f = *_f; + return f; + } + + // wait for all computing threads to finish and stop all threads + // may be called asynchronously to not pause the calling thread while waiting + // if isWait == true, all the functions in the queue are run, otherwise the queue is cleared without running the functions + void stop(bool isWait = false) { + if (!isWait) { + if (this->isStop) + return; + this->isStop = true; + for (int i = 0, n = this->size(); i < n; ++i) { + *this->flags[i] = true; // command the threads to stop + } + this->clear_queue(); // empty the queue + } + else { + if (this->isDone || this->isStop) + return; + this->isDone = true; // give the waiting threads a command to finish + } + { + std::unique_lock lock(this->mutex); + this->cv.notify_all(); // stop all waiting threads + } + for (int i = 0; i < static_cast(this->threads.size()); ++i) { // wait for the computing threads to finish + if (this->threads[i]->joinable()) + this->threads[i]->join(); + } + // if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads + // therefore delete them here + this->clear_queue(); + this->threads.clear(); + this->flags.clear(); + } + + template + auto push(F && f, Rest&&... rest) ->std::future { + auto pck = std::make_shared>( + std::bind(std::forward(f), std::placeholders::_1, std::forward(rest)...) + ); + auto _f = new std::function([pck](int id) { + (*pck)(id); + }); + ++this->nPending; + this->q.push(_f); + std::unique_lock lock(this->mutex); + this->cv.notify_one(); + return pck->get_future(); + } + + // run the user's function that excepts argument int - id of the running thread. returned value is templatized + // operator returns std::future, where the user can get the result and rethrow the catched exceptins + template + auto push(F && f) ->std::future { + auto pck = std::make_shared>(std::forward(f)); + auto _f = new std::function([pck](int id) { + (*pck)(id); + }); + ++this->nPending; + this->q.push(_f); + std::unique_lock lock(this->mutex); + this->cv.notify_one(); + return pck->get_future(); + } + + + private: + + // deleted + thread_pool(const thread_pool &);// = delete; + thread_pool(thread_pool &&);// = delete; + thread_pool & operator=(const thread_pool &);// = delete; + thread_pool & operator=(thread_pool &&);// = delete; + + void set_thread(int i) { + std::shared_ptr> flag(this->flags[i]); // a copy of the shared ptr to the flag + auto f = [this, i, flag/* a copy of the shared ptr to the flag */]() { + std::atomic & _flag = *flag; + std::function * _f; + bool isPop = this->q.pop(_f); + while (true) { + while (isPop) { // if there is anything in the queue + --this->nPending; + std::unique_ptr> func(_f); // at return, delete the function even if an exception occurred + (*_f)(i); + if (_flag) + return; // the thread is wanted to stop, return even if the queue is not empty yet + else + isPop = this->q.pop(_f); + } + // the queue is empty here, wait for the next command + std::unique_lock lock(this->mutex); + ++this->nWaiting; + this->cv.wait(lock, [this, &_f, &isPop, &_flag]() { isPop = this->q.pop(_f); return isPop || this->isDone || _flag; }); + --this->nWaiting; + if (!isPop) + return; // if the queue is empty and this->isDone == true or *flag then return + } + }; + this->threads[i].reset(new std::thread(f)); // compiler may not support std::make_unique() + } + + void init() { this->nWaiting = 0; this->nPending = 0; this->isStop = false; this->isDone = false; } + + std::vector> threads; + std::vector>> flags; + detail::Queue *> q; + std::atomic isDone; + std::atomic isStop; + std::atomic nWaiting; // how many threads are waiting + std::atomic nPending; // how many tasks are waiting + + std::mutex mutex; + std::condition_variable cv; + }; + +} + +#endif // __ctpl_stl_thread_pool_H__ \ No newline at end of file diff --git a/src/main/protocol/memory/habboclient/windows/WindowsHabboClient.java b/src/main/protocol/memory/habboclient/windows/WindowsHabboClient.java index f5ba48e..1c5ab16 100644 --- a/src/main/protocol/memory/habboclient/windows/WindowsHabboClient.java +++ b/src/main/protocol/memory/habboclient/windows/WindowsHabboClient.java @@ -1,5 +1,6 @@ package main.protocol.memory.habboclient.windows; +import main.misc.Cacher; import main.protocol.HConnection; import main.protocol.HMessage; import main.protocol.TrafficListener; @@ -32,22 +33,61 @@ public class WindowsHabboClient extends HabboClient { @Override public List getRC4cached() { - return new ArrayList<>(); + List result = new ArrayList<>(); + try { + List possibleResults = readPossibleBytes(true); + + if (possibleResults == null) + return new ArrayList<>(); + + for (String s : possibleResults) + result.add(hexStringToByteArray(s)); + } catch (IOException | URISyntaxException e) { + e.printStackTrace(); + } + return result; } - private ArrayList readPossibleBytes() throws IOException, URISyntaxException { - ProcessBuilder pb = new ProcessBuilder(new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).getParent() + "\\G-WinMem.exe", hConnection.getClientHostAndPort().substring(0, hConnection.getClientHostAndPort().indexOf(':')) , Integer.toString(hConnection.getPort())); + private ArrayList readPossibleBytes(boolean useCache) throws IOException, URISyntaxException { + ProcessBuilder pb = null; + List cachedOffsets = (List) Cacher.get("RC4Offsets"); + StringJoiner joiner = new StringJoiner(" "); + + if (useCache) { + if (cachedOffsets == null) { + return null; + } + + for (String s : cachedOffsets) { + joiner.add(s); + } + } + + if (!useCache) + pb = new ProcessBuilder(new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).getParent() + "\\G-WinMem.exe", hConnection.getClientHostAndPort().substring(0, hConnection.getClientHostAndPort().indexOf(':')) , Integer.toString(hConnection.getPort())); + else + pb = new ProcessBuilder(new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).getParent() + "\\G-WinMem.exe", hConnection.getClientHostAndPort().substring(0, hConnection.getClientHostAndPort().indexOf(':')) , Integer.toString(hConnection.getPort()), "-c" + joiner.toString()); + + Process p = pb.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); String line; ArrayList possibleData = new ArrayList<>(); + cachedOffsets = new ArrayList<>(); + + int count = 0; while((line = reader.readLine()) != null) { if (line.length() > 1) { - possibleData.add(line); + if (!useCache && (count++ % 2 == 0)) { + cachedOffsets.add(line); + } + else + possibleData.add(line); } } + Cacher.put("RC4Offsets", cachedOffsets); p.destroy(); return possibleData; } @@ -56,7 +96,7 @@ public class WindowsHabboClient extends HabboClient { public List getRC4possibilities() { List result = new ArrayList<>(); try { - ArrayList possibleData = readPossibleBytes(); + ArrayList possibleData = readPossibleBytes(false); for (String possibleHexStr : possibleData) { result.add(hexStringToByteArray(possibleHexStr));