diff --git a/.gitignore b/.gitignore
index 01a744d..8e86036 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,9 @@
.idea/
out/
G-Earth2.iml
+/G-WinMem/.vs
+/G-WinMem/x64
+/G-WinMem/G-WinMem/x64
/Extensions/
G-Earth.iml
+/G-EarthWindows.iml
\ No newline at end of file
diff --git a/G-WinMem/G-WinMem.sln b/G-WinMem/G-WinMem.sln
new file mode 100644
index 0000000..65152d4
--- /dev/null
+++ b/G-WinMem/G-WinMem.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27703.2018
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "G-WinMem", "G-WinMem\G-WinMem.vcxproj", "{D445BBD6-23E4-40AD-BB05-39E0401D7421}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D445BBD6-23E4-40AD-BB05-39E0401D7421}.Debug|x64.ActiveCfg = Debug|x64
+ {D445BBD6-23E4-40AD-BB05-39E0401D7421}.Debug|x64.Build.0 = Debug|x64
+ {D445BBD6-23E4-40AD-BB05-39E0401D7421}.Debug|x86.ActiveCfg = Debug|Win32
+ {D445BBD6-23E4-40AD-BB05-39E0401D7421}.Debug|x86.Build.0 = Debug|Win32
+ {D445BBD6-23E4-40AD-BB05-39E0401D7421}.Release|x64.ActiveCfg = Release|x64
+ {D445BBD6-23E4-40AD-BB05-39E0401D7421}.Release|x64.Build.0 = Release|x64
+ {D445BBD6-23E4-40AD-BB05-39E0401D7421}.Release|x86.ActiveCfg = Release|Win32
+ {D445BBD6-23E4-40AD-BB05-39E0401D7421}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {CDDBAEFF-CFB7-4167-88D9-015827207E0C}
+ EndGlobalSection
+EndGlobal
diff --git a/G-WinMem/G-WinMem/G-WinMem.cpp b/G-WinMem/G-WinMem/G-WinMem.cpp
new file mode 100644
index 0000000..dfc79e5
Binary files /dev/null and b/G-WinMem/G-WinMem/G-WinMem.cpp differ
diff --git a/G-WinMem/G-WinMem/G-WinMem.vcxproj b/G-WinMem/G-WinMem/G-WinMem.vcxproj
new file mode 100644
index 0000000..58e6a36
--- /dev/null
+++ b/G-WinMem/G-WinMem/G-WinMem.vcxproj
@@ -0,0 +1,169 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 15.0
+ {D445BBD6-23E4-40AD-BB05-39E0401D7421}
+ Win32Proj
+ GWinMem
+ 10.0.16299.0
+
+
+
+ Application
+ true
+ v141
+ Unicode
+
+
+ Application
+ false
+ v141
+ true
+ Unicode
+
+
+ Application
+ true
+ v141
+ Unicode
+
+
+ Application
+ false
+ v141
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ false
+
+
+
+ Use
+ Level3
+ Disabled
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ NotUsing
+ Level3
+ Disabled
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ stdcpp17
+
+
+ Console
+ true
+
+
+
+
+ Use
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Use
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+
\ 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
new file mode 100644
index 0000000..ebe7bb6
--- /dev/null
+++ b/G-WinMem/G-WinMem/G-WinMem.vcxproj.filters
@@ -0,0 +1,45 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/G-WinMem/G-WinMem/G-WinMem.vcxproj.user b/G-WinMem/G-WinMem/G-WinMem.vcxproj.user
new file mode 100644
index 0000000..be25078
--- /dev/null
+++ b/G-WinMem/G-WinMem/G-WinMem.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ 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..5de022a
--- /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::cerr << "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::cerr << "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::cerr << "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/G-WinMem/G-WinMem/stdafx.cpp b/G-WinMem/G-WinMem/stdafx.cpp
new file mode 100644
index 0000000..56288a9
Binary files /dev/null and b/G-WinMem/G-WinMem/stdafx.cpp differ
diff --git a/G-WinMem/G-WinMem/stdafx.h b/G-WinMem/G-WinMem/stdafx.h
new file mode 100644
index 0000000..94d4ed8
Binary files /dev/null and b/G-WinMem/G-WinMem/stdafx.h differ
diff --git a/G-WinMem/G-WinMem/targetver.h b/G-WinMem/G-WinMem/targetver.h
new file mode 100644
index 0000000..567cd34
Binary files /dev/null and b/G-WinMem/G-WinMem/targetver.h differ
diff --git a/src/g_earth/protocol/memory/habboclient/windows/WindowsHabboClient.java b/src/g_earth/protocol/memory/habboclient/windows/WindowsHabboClient.java
index 6bc9148..3410787 100644
--- a/src/g_earth/protocol/memory/habboclient/windows/WindowsHabboClient.java
+++ b/src/g_earth/protocol/memory/habboclient/windows/WindowsHabboClient.java
@@ -1,312 +1,142 @@
package g_earth.protocol.memory.habboclient.windows;
-//import com.sun.jna.Memory;
-//import com.sun.jna.Native;
-//import com.sun.jna.Pointer;
-//import com.sun.jna.platform.win32.Kernel32;
-//import com.sun.jna.platform.win32.User32;
-//import com.sun.jna.platform.win32.WinBase;
-//import com.sun.jna.platform.win32.WinNT;
-//import com.sun.jna.ptr.IntByReference;
-import g_earth.protocol.HConnection;
-import g_earth.protocol.memory.habboclient.HabboClient;
+import g_earth.misc.Cacher;
+import g_earth.protocol.HConnection;
+import g_earth.protocol.HMessage;
+import g_earth.protocol.TrafficListener;
+import g_earth.protocol.memory.habboclient.HabboClient;
+import org.json.simple.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URISyntaxException;
import java.util.*;
/**
* Created by Jeunez on 27/06/2018.
*/
-
-/*
- * not functional class
- */
-
public class WindowsHabboClient extends HabboClient {
public WindowsHabboClient(HConnection connection) {
super(connection);
+
+ connection.addTrafficListener(0, message -> {
+ if (message.getDestination() == HMessage.Side.TOSERVER && message.getPacket().headerId() == PRODUCTIONID) {
+ production = message.getPacket().readString();
+ }
+ });
+ }
+
+ private static final int PRODUCTIONID = 4000;
+ private String production = "";
+
+ private String getOffsetsCacheKey() {
+ return "RC4Offsets";
+ }
+
+ private String getOffsetsRevision() {
+ return production;
}
@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(boolean useCache) throws IOException, URISyntaxException {
+ ProcessBuilder pb = null;
+ JSONObject revisionList = (JSONObject) Cacher.get(getOffsetsCacheKey());
+
+ if (revisionList == null) {
+ Cacher.put(getOffsetsCacheKey(), new JSONObject());
+ revisionList = (JSONObject) Cacher.get(getOffsetsCacheKey()); // refresh
+ }
+
+ List cachedOffsets = (List) revisionList.get(getOffsetsRevision());
+ 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<>();
+
+ if (cachedOffsets == null) {
+ cachedOffsets = new ArrayList<>();
+ }
+
+
+ int count = 0;
+ while((line = reader.readLine()) != null) {
+ if (line.length() > 1) {
+ if (!useCache && (count++ % 2 == 0)) {
+ if (!cachedOffsets.contains(line)) {
+ cachedOffsets.add(line);
+ }
+ }
+ else
+ possibleData.add(line);
+ }
+ }
+ revisionList.put(getOffsetsRevision(), cachedOffsets);
+ Cacher.put(getOffsetsCacheKey(), revisionList);
+ p.destroy();
+ return possibleData;
}
@Override
public List getRC4possibilities() {
- return null;
- }
-//
-// private static final boolean DEBUG = true;
-// private List possibleFlashTasks;
-//
-// static Kernel32 kernel32 = (Kernel32) Native.loadLibrary("kernel32",Kernel32.class);
-// static User32 user32 = (User32) Native.loadLibrary("user32", User32.class);
-//
-// public static int PROCESS_VM_READ= 0x0010;
-// public static int PROCESS_VM_WRITE = 0x0020;
-// public static int PROCESS_VM_OPERATION = 0x0008;
-//
-//
-// public WindowsHabboClient(HConnection connection) {
-// super(connection);
-// }
-//
-// static class WindowsTask {
-// public String name;
-// public int PID;
-// public String session_name;
-// public int sessionNumber;
-// public int mem_usage;
-//
-// public WindowsTask(String name, int PID, String sessions_name, int sessionNumber, int mem_usage) {
-// this.name = name;
-// this.PID = PID;
-// this.session_name = sessions_name;
-// this.sessionNumber = sessionNumber;
-// this.mem_usage = mem_usage;
-// }
-//
-// @Override
-// public String toString() {
-// return "name: " + name + ", PID: " + PID + ", memory: " + mem_usage;
-// }
-// }
-//
-// private static List execute_command(String command) {
-// List result = new ArrayList<>();
-// try {
-// Process process = Runtime.getRuntime().exec(command);
-// BufferedReader reader=new BufferedReader( new InputStreamReader(process.getInputStream()));
-// String s;
-// while ((s = reader.readLine()) != null){
-// result.add(s);
-// }
-// } catch (IOException e) {
-// e.printStackTrace();
-// }
-// return result;
-// }
-// private static List splitStringExtra(String s, String regex ) {
-// String[] split = s.split(regex);
-//
-// List realSplit = new ArrayList<>();
-// for (String spli : split) {
-// if (!spli.equals("") && !spli.equals(" ")) {
-// realSplit.add(spli);
-// }
-// }
-//
-// return realSplit;
-// }
-// private static List parseTaskList(List lines) {
-// List windowsTasks = new ArrayList<>();
-//
-// final int ARG_COUNT = 5;
-// boolean listHasStarted = false;
-// int[] paramLengths = new int[ARG_COUNT];
-// for (String line : lines) {
-//
-// if (!listHasStarted && line.startsWith("=")) {
-// List splitted = splitStringExtra(line, " ");
-// if (splitted.size() == ARG_COUNT) {
-// listHasStarted = true;
-// for (int i = 0; i < ARG_COUNT; i++) {
-// paramLengths[i] = splitted.get(i).length();
-// }
-// }
-// }
-// else if (listHasStarted && splitStringExtra(line, " ").size() >= 5) {
-// int v = 0;
-// String[] args = new String[ARG_COUNT];
-// for (int i = 0; i < ARG_COUNT; i++) {
-// int endindex = v + paramLengths[i];
-// args[i] = trim(line.substring(v, endindex));
-// v = endindex + 1;
-// }
-//
-// WindowsTask task = new WindowsTask(
-// args[0],
-// Integer.parseInt(args[1]),
-// args[2],
-// Integer.parseInt(args[3]),
-// obtainMemorySizeFromCMDString(args[4])
-// );
-//
-// windowsTasks.add(task);
-// }
-//
-// }
-//
-// return windowsTasks;
-// }
-// private static String trim(String s) {
-// int start = 0;
-// for (int i = 0; i < s.length(); i++) {
-// if (s.charAt(i) == ' ') start++;
-// else break;
-// }
-//
-// int end = s.length();
-// for (int i = s.length() - 1; i >= 0; i--) {
-// if (s.charAt(i) == ' ') end--;
-// else break;
-// }
-//
-// return s.substring(start, end);
-// }
-// private static int obtainMemorySizeFromCMDString(String s) {
-// s = s.replaceAll("[^0-9A-Z]","")
-// .replace("K","000")
-// .replace("M", "000000")
-// .replace("G", "000000000");
-// return Integer.parseInt(s);
-// }
-//
-// private void obtain_PIDs() {
-// int headPID = -1;
-//
-//
-// String command1 = "cmd /C netstat -a -o -n | findstr "+hConnection.getClientHostAndPort()+" | findstr ESTABLISHED";
-// List connections = execute_command(command1);
-// for (String s : connections) {
-// List realSplit = splitStringExtra(s, " ");
-//
-// if (realSplit.size() > 1 && realSplit.get(1).equals(hConnection.getClientHostAndPort())) {
-// headPID = Integer.parseInt(realSplit.get(4));
-// }
-// }
-//
-//
-//
-// String command2 = "cmd /C tasklist";
-// List tasks = execute_command(command2);
-// List taskList = parseTaskList(tasks);
-//
-// WindowsTask matchWithPID = null;
-// int i = 0;
-// while (matchWithPID == null && i < taskList.size()) {
-// WindowsTask task = taskList.get(i);
-// if (task.PID == headPID) {
-// matchWithPID = task;
-// }
-// i++;
-// }
-//
-// possibleFlashTasks = new ArrayList<>();
-// if (matchWithPID != null) {
-// for (WindowsTask task : taskList) {
-// if (task.name.equals(matchWithPID.name)) {
-// possibleFlashTasks.add(task);
-// }
-// }
-// }
-//
-//
-//
-// }
-//
-// @Override
-// public List getRC4possibilities() {
-// obtain_PIDs();
-//
-// List possibilities = new ArrayList<>();
-//
-// int[] count = {0};
-// for (int i = 0; i < possibleFlashTasks.size(); i++) {
-// WindowsTask task = possibleFlashTasks.get(i);
-// if (DEBUG) System.out.println("Potential task " + task);
-//
-// new Thread(() -> {
-// List sublist = getRC4possibilities(task.PID, task.mem_usage);
-//
-// synchronized (count) {
-// possibilities.addAll(sublist);
-// count[0] ++;
-// }
-//
-// }).start();
-// }
-//
-// while (count[0] != possibleFlashTasks.size() + 1) { // the +1 is temporary, to keep this function blocking untill it's functional
-// try {
-// Thread.sleep(1);
-// } catch (InterruptedException e) {
-// e.printStackTrace();
-// }
-// }
-//
-// return possibilities;
-// }
-//
-// public List getRC4possibilities(int processID, int processMemorySize) {
-// List result = new ArrayList<>();
-//
-//// user32.GetWindowThreadProcessId()
-// WinNT.HANDLE process = kernel32.OpenProcess(PROCESS_VM_READ|PROCESS_VM_OPERATION, true, processID);
-//
-// IntByReference test = new IntByReference(0);
-// Memory output = new Memory(100000);
-// System.out.println(kernel32.ReadProcessMemory(process, new Pointer(0), output, 100000, test));
-// System.out.println(test.getValue());
-//
-// int[] counter = new int[256];
-// int p = 0;
-// while (p < output.size()) {
-// counter[(output.getByte(p) + 256) % 256] ++;
-// p += 4;
-// }
-//
-//// for (int i = 0; i < counter.length; i++) {
-//// System.out.println("counter " + i + " = " + counter[i]);
-//// }
-//
-//// WinNT.HANDLE process = kernel32.OpenProcess(PROCESS_VM_READ|PROCESS_VM_OPERATION, true, processID);
-//// Memory out = new Memory(processMemorySize);
-//// kernel32.ReadProcessMemory(process, new Pointer(0), out, processMemorySize, new IntByReference());
-////
-//// int[] counter = new int[256];
-//// int p = 0;
-//// while (p < out.size()) {
-//// counter[((out.getByte(p)) + 256) % 256] ++;
-//// p += 4;
-//// }
-////
-//// HashMap> mapper = new HashMap<>();
-//// HashSet allvalues = new HashSet<>();
-//// for (int i = 0; i < counter.length; i++) {
-//// if (!mapper.containsKey(counter[i])) {
-//// mapper.put(counter[i], new ArrayList<>());
-//// }
-//// mapper.get(counter[i]).add(i);
-//// allvalues.add(counter[i]);
-//// }
-////// System.out.println(allvalues.size());
-//// ArrayList allvalues2 = new ArrayList<>(allvalues);
-//// allvalues2.sort(Integer::compareTo);
-////
-//// StringBuilder sttt = new StringBuilder();
-//// sttt.append("process ").append(processID).append(", ");
-//// for (int i = 1; i < Math.min(4, allvalues2.size()+1); i++) {
-//// int occ = allvalues2.get(allvalues2.size() - i);
-//// sttt .append(i)
-//// .append(": ")
-//// .append(mapper.get(occ).get(0))
-//// .append(" with ")
-//// .append(occ)
-//// .append(" occurences, ");
-//// }
-//// System.out.println(sttt);
-//
-// return result;
-// }
-//
-// public static void main(String[] args) {
-// String command2 = "cmd /C tasklist";
-// List tasks = execute_command(command2);
-// List taskList = parseTaskList(tasks);
-//
-// System.out.println("t");
-// }
+ List result = new ArrayList<>();
+ try {
+ ArrayList possibleData = readPossibleBytes(false);
+ for (String possibleHexStr : possibleData) {
+ result.add(hexStringToByteArray(possibleHexStr));
+ }
+ } catch (IOException | URISyntaxException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ public static byte[] hexStringToByteArray(String s) {
+ int len = s.length();
+ byte[] data = new byte[len / 2];
+ for (int i = 0; i < len; i += 2) {
+ data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ + Character.digit(s.charAt(i+1), 16));
+ }
+ return data;
+ }
}