Skip to content

Commit 313f8e3

Browse files
authored
Add files via upload
1 parent ad146b4 commit 313f8e3

41 files changed

Lines changed: 3072 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
project(CodecaveDumper)
3+
4+
set(CMAKE_CXX_STANDARD 17)
5+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
6+
7+
include_directories(include)
8+
9+
add_executable(codecave_dumper
10+
main.cpp
11+
codecave_dumper.cpp
12+
codecave_dumper_cli.cpp
13+
)

codecave_dumper.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#include "codecave_dumper.h"
2+
#include <iostream>
3+
#include <fstream>
4+
#include <regex>
5+
#include <algorithm>
6+
7+
const DWORD CodecaveDumper::READABLE_PROTECTIONS[] = {
8+
MEM_PAGE_READONLY,
9+
MEM_PAGE_READWRITE,
10+
MEM_PAGE_WRITECOPY,
11+
MEM_PAGE_EXECUTE_READ,
12+
MEM_PAGE_EXECUTE_READWRITE
13+
};
14+
15+
HANDLE CodecaveDumper::getHandle(DWORD pid) {
16+
return OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
17+
}
18+
19+
std::vector<char> CodecaveDumper::readMemory(HANDLE handle, LPVOID address, SIZE_T size) {
20+
std::vector<char> buffer(size);
21+
SIZE_T bytesRead;
22+
23+
if (!ReadProcessMemory(handle, address, buffer.data(), size, &bytesRead)) {
24+
throw std::runtime_error("Failed to read process memory");
25+
}
26+
27+
buffer.resize(bytesRead);
28+
return buffer;
29+
}
30+
31+
bool CodecaveDumper::isReadable(DWORD protect) {
32+
const size_t size = sizeof(READABLE_PROTECTIONS) / sizeof(READABLE_PROTECTIONS[0]);
33+
return std::find(READABLE_PROTECTIONS,
34+
READABLE_PROTECTIONS + size,
35+
protect) != READABLE_PROTECTIONS + size;
36+
}
37+
38+
std::vector<std::string> CodecaveDumper::extractData(const std::vector<char>& data, size_t minLength) {
39+
static const auto junkPattern = std::regex(R"(^[0-9A-F]+$|^[A-Z]{1,3}\d+$|^\W+$|^.{1,3}$|(.)\1{3,})",
40+
std::regex::optimize);
41+
42+
std::vector<std::string> strings;
43+
strings.reserve(1000);
44+
45+
constexpr size_t CHUNK_SIZE = 4096;
46+
std::string current;
47+
current.reserve(256);
48+
49+
for (size_t i = 0; i < data.size(); i += CHUNK_SIZE) {
50+
const size_t chunk_end = (i + CHUNK_SIZE < data.size()) ? i + CHUNK_SIZE : data.size();
51+
for (char byte : data) {
52+
if (isprint(byte)) {
53+
current += byte;
54+
} else if (!current.empty()) {
55+
if (current.length() >= minLength &&
56+
!std::regex_match(current, junkPattern) &&
57+
std::any_of(current.begin(), current.end(), ::isalnum)) {
58+
strings.push_back(std::move(current));
59+
}
60+
current.clear();
61+
current.reserve(256);
62+
}
63+
}
64+
}
65+
66+
if (current.length() >= minLength &&
67+
!std::regex_match(current, junkPattern) &&
68+
std::any_of(current.begin(), current.end(), ::isalnum)) {
69+
strings.push_back(std::move(current));
70+
}
71+
72+
return strings;
73+
}
74+
75+
void CodecaveDumper::dump(DWORD pid) {
76+
try {
77+
HANDLE handle = getHandle(pid);
78+
if (handle == NULL) {
79+
throw std::runtime_error("Failed to open process");
80+
}
81+
82+
std::cout << "\nStarting codecave dump for PID: " << pid << std::endl;
83+
84+
std::string outputFile = std::to_string(pid) + "_dump.txt";
85+
LPVOID address = nullptr;
86+
MEMORY_BASIC_INFORMATION memInfo;
87+
std::set<std::string> uniqueStrings;
88+
size_t regionsAnalyzed = 0;
89+
size_t totalRegions = 0;
90+
91+
while (VirtualQueryEx(handle, address, &memInfo, sizeof(memInfo))) {
92+
totalRegions++;
93+
if (isReadable(memInfo.Protect)) {
94+
try {
95+
auto chunk = readMemory(handle, memInfo.BaseAddress, memInfo.RegionSize);
96+
auto strings = extractData(chunk);
97+
uniqueStrings.insert(std::make_move_iterator(strings.begin()),
98+
std::make_move_iterator(strings.end()));
99+
regionsAnalyzed++;
100+
}
101+
catch (const std::exception&) {
102+
// Skip failed regions
103+
}
104+
}
105+
address = (LPVOID)((DWORD_PTR)memInfo.BaseAddress + memInfo.RegionSize);
106+
}
107+
108+
std::ofstream outFile(outputFile, std::ios::binary);
109+
for (const auto& str : uniqueStrings) {
110+
outFile << str << '\n';
111+
}
112+
113+
std::cout << "\nDump complete!" << std::endl;
114+
std::cout << "Analyzed " << regionsAnalyzed << "/" << totalRegions << " regions" << std::endl;
115+
std::cout << "Found " << uniqueStrings.size() << " unique strings" << std::endl;
116+
std::cout << "Results saved to: " << outputFile << std::endl;
117+
118+
CloseHandle(handle);
119+
}
120+
catch (const std::exception& e) {
121+
std::cerr << "Error: " << e.what() << std::endl;
122+
}
123+
}

codecave_dumper_cli.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "codecave_dumper_cli.h"
2+
#include <iostream>
3+
#include <tlhelp32.h>
4+
5+
void CodecaveDumperCLI::listProcesses() {
6+
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
7+
if (snapshot == INVALID_HANDLE_VALUE) return;
8+
9+
PROCESSENTRY32W pe32;
10+
pe32.dwSize = sizeof(pe32);
11+
12+
std::cout << "\nAvailable Python processes:" << std::endl;
13+
if (Process32FirstW(snapshot, &pe32)) {
14+
do {
15+
std::wstring processName = pe32.szExeFile;
16+
if (processName.find(L"python") != std::wstring::npos) {
17+
std::wcout << pe32.th32ProcessID << L"\t" << processName << std::endl;
18+
}
19+
} while (Process32NextW(snapshot, &pe32));
20+
}
21+
22+
CloseHandle(snapshot);
23+
}
24+
25+
void CodecaveDumperCLI::run() {
26+
while (true) {
27+
std::cout << "Codecave Hook By Libalpm Program Dumper" << std::endl;
28+
std::cout << "\nMenu Options:" << std::endl;
29+
std::cout << "1. List Python Processes" << std::endl;
30+
std::cout << "2. Dump Process Memory" << std::endl;
31+
std::cout << "3. Exit" << std::endl;
32+
33+
std::string choice;
34+
std::cout << "\nEnter your choice (1-3): ";
35+
std::getline(std::cin, choice);
36+
37+
if (choice == "1") {
38+
listProcesses();
39+
}
40+
else if (choice == "2") {
41+
std::cout << "Enter PID to dump: ";
42+
std::string pidStr;
43+
std::getline(std::cin, pidStr);
44+
try {
45+
DWORD pid = std::stoul(pidStr);
46+
dumper.dump(pid);
47+
}
48+
catch (const std::exception&) {
49+
std::cerr << "Error: Please enter a valid PID" << std::endl;
50+
}
51+
}
52+
else if (choice == "3") {
53+
std::cout << "\nGoodbye!" << std::endl;
54+
break;
55+
}
56+
else {
57+
std::cout << "Invalid choice. Please try again." << std::endl;
58+
}
59+
}
60+
}

include/codecave_dumper.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
#include <windows.h>
3+
#include <string>
4+
#include <vector>
5+
#include <set>
6+
7+
// Pyarmors constants
8+
#define MEM_PAGE_READONLY 0x02
9+
#define MEM_PAGE_READWRITE 0x04
10+
#define MEM_PAGE_WRITECOPY 0x08
11+
#define MEM_PAGE_EXECUTE_READ 0x20
12+
#define MEM_PAGE_EXECUTE_READWRITE 0x40
13+
14+
class CodecaveDumper {
15+
private:
16+
static const DWORD READABLE_PROTECTIONS[];
17+
HANDLE getHandle(DWORD pid);
18+
std::vector<char> readMemory(HANDLE handle, LPVOID address, SIZE_T size);
19+
bool isReadable(DWORD protect);
20+
std::vector<std::string> extractData(const std::vector<char>& data, size_t minLength = 4);
21+
22+
public:
23+
void dump(DWORD pid);
24+
};

include/codecave_dumper_cli.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#pragma once
2+
#include "codecave_dumper.h"
3+
4+
class CodecaveDumperCLI {
5+
private:
6+
CodecaveDumper dumper;
7+
void listProcesses();
8+
9+
public:
10+
void run();
11+
};

main.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include "codecave_dumper_cli.h"
2+
3+
int main() {
4+
CodecaveDumperCLI cli;
5+
cli.run();
6+
return 0;
7+
}

0 commit comments

Comments
 (0)