First commit

vmread
MisterY52 4 years ago
parent 1a3c1442d7
commit b7d90b601e

@ -1,2 +1,4 @@
# apex_dma_kvm_pub
Apex Legends QEMU/KVM hack
UnknownCheats thread: https://www.unknowncheats.me/forum/apex-legends/406426-kvm-vmread-apex-esp-aimbot.html

@ -0,0 +1,297 @@
#include "prediction.h"
extern bool firing_range;
uint64_t Entity::Observing(WinProcess& mem, uint64_t entitylist)
{
uint64_t index = *(uint64_t*)(buffer + OFFSET_OBSERVING_TARGET);
index &= ENT_ENTRY_MASK;
if (index > 0)
{
uint64_t centity2 = mem.Read<uint64_t>(entitylist + ((uint64_t)index << 5));
return centity2;
}
return 0;
}
int Entity::getTeamId()
{
return *(int*)(buffer + OFFSET_TEAM);
}
int Entity::getHealth()
{
return *(int*)(buffer + OFFSET_HEALTH);
}
int Entity::getShield()
{
return *(int*)(buffer + OFFSET_SHIELD);
}
Vector Entity::getAbsVelocity()
{
return *(Vector*)(buffer + OFFSET_ABS_VELOCITY);
}
Vector Entity::getPosition()
{
return *(Vector*)(buffer + OFFSET_ORIGIN);
}
bool Entity::isPlayer()
{
return *(uint64_t*)(buffer + OFFSET_NAME) == 125780153691248;
}
bool Entity::isDummy()
{
return *(int*)(buffer + OFFSET_TEAM) == 97;
}
bool Entity::isKnocked()
{
return *(int*)(buffer + OFFSET_BLEED_OUT_STATE) > 0;
}
bool Entity::isAlive()
{
return *(int*)(buffer + OFFSET_LIFE_STATE) == 0;
}
float Entity::lastVisTime()
{
return *(float*)(buffer + OFFSET_VISIBLE_TIME);
}
Vector Entity::getBonePosition(WinProcess& mem, int id)
{
Vector position = getPosition();
uintptr_t boneArray = *(uintptr_t*)(buffer + OFFSET_BONES);
Vector bone = Vector();
uint32_t boneloc = (id * 0x30);
Bone bo = {};
bo = mem.Read<Bone>(boneArray + boneloc);
bone.x = bo.x + position.x;
bone.y = bo.y + position.y;
bone.z = bo.z + position.z;
return bone;
}
QAngle Entity::GetSwayAngles()
{
return *(QAngle*)(buffer + OFFSET_BREATH_ANGLES);
}
QAngle Entity::GetViewAngles()
{
return *(QAngle*)(buffer + OFFSET_VIEWANGLES);
}
Vector Entity::GetViewAnglesV()
{
return *(Vector*)(buffer + OFFSET_VIEWANGLES);
}
void Entity::SetViewAngles(WinProcess& mem, SVector angles)
{
mem.Write<SVector>(ptr + OFFSET_VIEWANGLES, angles);
}
void Entity::SetViewAngles(WinProcess& mem, QAngle& angles)
{
SetViewAngles(mem, SVector(angles));
}
Vector Entity::GetCamPos()
{
return *(Vector*)(buffer + OFFSET_CAMERAPOS);
}
QAngle Entity::GetRecoil()
{
return *(QAngle*)(buffer + OFFSET_AIMPUNCH);
}
bool Item::isItem()
{
return *(int*)(buffer + OFFSET_ITEM_GLOW) >= 1358917120 && *(int*)(buffer + OFFSET_ITEM_GLOW) <= 1646297344;
}
bool Item::isGlowing()
{
return *(int*)(buffer + OFFSET_ITEM_GLOW) == 1363184265;
}
void Item::enableGlow(WinProcess& mem)
{
mem.Write<int>(ptr + OFFSET_ITEM_GLOW, 1363184265);
}
void Item::disableGlow(WinProcess& mem)
{
mem.Write<int>(ptr + OFFSET_ITEM_GLOW, 1411417991);
}
Vector Item::getPosition()
{
return *(Vector*)(buffer + OFFSET_ORIGIN);
}
float CalculateFov(Entity& from, Entity& target)
{
QAngle ViewAngles = from.GetViewAngles();
Vector LocalCamera = from.GetCamPos();
Vector EntityPosition = target.getPosition();
QAngle Angle = Math::CalcAngle(LocalCamera, EntityPosition);
return Math::GetFov(ViewAngles, Angle);
}
QAngle CalculateBestBoneAim(WinProcess& mem, Entity& from, uintptr_t t, float max_fov)
{
Entity target = getEntity(mem, t);
if(firing_range)
{
if (!target.isAlive())
{
return QAngle(0, 0, 0);
}
}
else
{
if (!target.isAlive() || target.isKnocked())
{
return QAngle(0, 0, 0);
}
}
Vector EntityPosition = target.getPosition();
Vector LocalPlayerPosition = from.getPosition();
float dist = LocalPlayerPosition.DistTo(EntityPosition);
int bone = 2;
if (dist < 500)
{
bone = 5;
}
Vector LocalCamera = from.GetCamPos();
Vector TargetBonePosition = target.getBonePosition(mem, bone);
QAngle CalculatedAngles = QAngle(0, 0, 0);
WeaponXEntity curweap = WeaponXEntity();
curweap.update(mem, from.ptr);
float BulletSpeed = curweap.get_projectile_speed();
float BulletGrav = curweap.get_projectile_gravity();
/*
//simple aim prediction
if (BulletSpeed > 1.f)
{
Vector LocalBonePosition = from.getBonePosition(mem, bone);
float VerticalTime = TargetBonePosition.DistTo(LocalBonePosition) / BulletSpeed;
TargetBonePosition.z += (BulletGrav * 0.5f) * (VerticalTime * VerticalTime);
float HorizontalTime = TargetBonePosition.DistTo(LocalBonePosition) / BulletSpeed;
TargetBonePosition += (target.getAbsVelocity() * HorizontalTime);
}
*/
//more accurate prediction
if (BulletSpeed > 1.f)
{
PredictCtx Ctx;
Ctx.StartPos = LocalCamera;
Ctx.TargetPos = TargetBonePosition;
Ctx.BulletSpeed = BulletSpeed - (BulletSpeed*0.08);
Ctx.BulletGravity = BulletGrav + (BulletGrav*0.05);
Ctx.TargetVel = target.getAbsVelocity();
if (BulletPredict(Ctx))
CalculatedAngles = QAngle{Ctx.AimAngles.x, Ctx.AimAngles.y, 0.f};
}
if (CalculatedAngles == QAngle(0, 0, 0))
CalculatedAngles = Math::CalcAngle(LocalCamera, TargetBonePosition);
QAngle ViewAngles = from.GetViewAngles();
QAngle SwayAngles = from.GetSwayAngles();
//remove sway and recoil
CalculatedAngles-=SwayAngles-ViewAngles;
Math::NormalizeAngles(CalculatedAngles);
QAngle Delta = CalculatedAngles - ViewAngles;
double fov = Math::GetFov(SwayAngles, CalculatedAngles);
if (fov > max_fov)
{
return QAngle(0, 0, 0);
}
double smooth = 12.0f;
Math::NormalizeAngles(Delta);
QAngle SmoothedAngles = ViewAngles + Delta/smooth;
return SmoothedAngles;
}
Entity getEntity(WinProcess& mem, uintptr_t ptr)
{
Entity entity = Entity();
entity.ptr = ptr;
mem.ReadMem(ptr, (uintptr_t)entity.buffer, sizeof(entity.buffer));
return entity;
}
Item getItem(WinProcess& mem, uintptr_t ptr)
{
Item entity = Item();
entity.ptr = ptr;
mem.ReadMem(ptr, (uintptr_t)entity.buffer, sizeof(entity.buffer));
return entity;
}
bool WorldToScreen(Vector from, float* m_vMatrix, int targetWidth, int targetHeight, Vector& to)
{
float w = m_vMatrix[12] * from.x + m_vMatrix[13] * from.y + m_vMatrix[14] * from.z + m_vMatrix[15];
if (w < 0.01f) return false;
to.x = m_vMatrix[0] * from.x + m_vMatrix[1] * from.y + m_vMatrix[2] * from.z + m_vMatrix[3];
to.y = m_vMatrix[4] * from.x + m_vMatrix[5] * from.y + m_vMatrix[6] * from.z + m_vMatrix[7];
float invw = 1.0f / w;
to.x *= invw;
to.y *= invw;
float x = targetWidth / 2;
float y = targetHeight / 2;
x += 0.5 * to.x * targetWidth + 0.5;
y -= 0.5 * to.y * targetHeight + 0.5;
to.x = x;
to.y = y;
to.z = 0;
return true;
}
void WeaponXEntity::update(WinProcess& mem, uint64_t LocalPlayer)
{
extern uint64_t g_Base;
uint64_t entitylist = g_Base + OFFSET_ENTITYLIST;
uint64_t wephandle = mem.Read<uint64_t>(LocalPlayer + OFFSET_WEAPON);
wephandle &= 0xffff;
uint64_t wep_entity = mem.Read<uint64_t>(entitylist + (wephandle << 5));
projectile_speed = mem.Read<float>(wep_entity + OFFSET_BULLET_SPEED);
projectile_scale = mem.Read<float>(wep_entity + OFFSET_BULLET_SCALE);
}
float WeaponXEntity::get_projectile_speed()
{
return projectile_speed;
}
float WeaponXEntity::get_projectile_gravity()
{
return 750.0f * projectile_scale;
}

@ -0,0 +1,73 @@
#include "Math.h"
#include "offsets.h"
#include "../vmread/hlapi/hlapi.h"
#define NUM_ENT_ENTRIES (1 << 12)
#define ENT_ENTRY_MASK (NUM_ENT_ENTRIES - 1)
typedef struct Bone
{
uint8_t pad1[0xCC];
float x;
uint8_t pad2[0xC];
float y;
uint8_t pad3[0xC];
float z;
}Bone;
class Entity
{
public:
uint64_t ptr;
uint8_t buffer[0x3FF0];
Vector getPosition();
bool isDummy();
bool isPlayer();
bool isKnocked();
bool isAlive();
float lastVisTime();
int getTeamId();
int getHealth();
int getShield();
Vector getAbsVelocity();
QAngle GetSwayAngles();
QAngle GetViewAngles();
Vector GetCamPos();
QAngle GetRecoil();
Vector GetViewAnglesV();
void SetViewAngles(WinProcess& mem, SVector angles);
void SetViewAngles(WinProcess& mem, QAngle& angles);
Vector getBonePosition(WinProcess& mem, int id);
uint64_t Observing(WinProcess& mem, uint64_t entitylist);
};
class Item
{
public:
uint64_t ptr;
uint8_t buffer[0x3FF0];
Vector getPosition();
bool isItem();
bool isGlowing();
void enableGlow(WinProcess& mem);
void disableGlow(WinProcess& mem);
};
class WeaponXEntity
{
public:
void update(WinProcess& mem, uint64_t LocalPlayer);
float get_projectile_speed();
float get_projectile_gravity();
private:
float projectile_scale;
float projectile_speed;
};
Entity getEntity(WinProcess& mem, uintptr_t ptr);
Item getItem(WinProcess& mem, uintptr_t ptr);
bool WorldToScreen(Vector from, float* m_vMatrix, int targetWidth, int targetHeight, Vector& to);
float CalculateFov(Entity& from, Entity& target);
QAngle CalculateBestBoneAim(WinProcess& mem, Entity& from, uintptr_t target, float max_fov);

@ -0,0 +1,44 @@
#include "Math.h"
void Math::NormalizeAngles(QAngle& angle)
{
while (angle.x > 89.0f)
angle.x -= 180.f;
while (angle.x < -89.0f)
angle.x += 180.f;
while (angle.y > 180.f)
angle.y -= 360.f;
while (angle.y < -180.f)
angle.y += 360.f;
}
QAngle Math::CalcAngle(const Vector& src, const Vector& dst)
{
QAngle angle = QAngle();
SVector delta = SVector((src.x - dst.x), (src.y - dst.y), (src.z - dst.z));
double hyp = sqrt(delta.x*delta.x + delta.y * delta.y);
angle.x = atan(delta.z / hyp) * (180.0f / M_PI);
angle.y = atan(delta.y / delta.x) * (180.0f / M_PI);
angle.z = 0;
if (delta.x >= 0.0) angle.y += 180.0f;
return angle;
}
double Math::GetFov(const QAngle& viewAngle, const QAngle& aimAngle)
{
QAngle delta = aimAngle - viewAngle;
NormalizeAngles(delta);
return sqrt(pow(delta.x, 2.0f) + pow(delta.y, 2.0f));
}
double Math::DotProduct(const Vector& v1, const float* v2)
{
return v1.x * v2[0] + v1.y * v2[1] + v1.z * v2[2];
}

@ -0,0 +1,30 @@
#include <math.h>
#include "vector.h"
struct SVector
{
float x;
float y;
float z;
SVector(float x1, float y1, float z1)
{
x = x1;
y = y1;
z = z1;
}
SVector(QAngle q)
{
x = q.x;
y = q.y;
z = q.z;
}
};
namespace Math
{
void NormalizeAngles(QAngle& angle);
double GetFov(const QAngle& viewAngle, const QAngle& aimAngle);
double DotProduct(const Vector& v1, const float* v2);
QAngle CalcAngle(const Vector& src, const Vector& dst);
}

@ -0,0 +1,758 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <random>
#include <chrono>
#include <iostream>
#include <cfloat>
#include "Game.h"
#include <thread>
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
FILE* dfile;
bool firing_range = false;
bool active = true;
uintptr_t aimentity = 0;
uintptr_t tmp_aimentity = 0;
uintptr_t lastaimentity = 0;
float max = 999.0f;
float max_dist = 200.0f*40.0f;
int team_player = 0;
int tmp_spec = 0, spectators = 0;
int tmp_all_spec = 0, allied_spectators = 0;
int playerId = 0;
int s_FOV = 15;
int toRead = 100;
int aim = false;
bool esp = false;
bool item_glow = false;
int safe_level = 0;
bool aiming = false;
bool actions_t = false;
bool esp_t = false;
bool aim_t = false;
bool vars_t = false;
bool item_t = false;
uint64_t g_Base;
uint64_t c_Base;
bool next = false;
bool valid = false;
bool lock = false;
typedef struct player
{
float dist = 0;
int entity_team = 0;
float boxMiddle = 0;
float h_y = 0;
float width = 0;
float height = 0;
float b_x = 0;
float b_y = 0;
bool knocked = false;
bool visible = false;
int health = 0;
int shield = 0;
}player;
struct Matrix
{
float matrix[16];
};
float lastvis_esp[100];
float lastvis_aim[100];
//////////////////////////////////////////////////////////////////////////////////////////////////
bool tmp = true;
void ProcessPlayer(WinProcess& mem, Entity& LPlayer, Entity& target, uint64_t entitylist, int index)
{
int entity_team = target.getTeamId();
if (target.Observing(mem, entitylist) == LPlayer.ptr)
{
if (entity_team == team_player)
{
tmp_all_spec++;
}
else
{
tmp_spec++;
}
}
Vector EntityPosition = target.getPosition();
Vector LocalPlayerPosition = LPlayer.getPosition();
float dist = LocalPlayerPosition.DistTo(EntityPosition);
if (dist > max_dist) return;
if (!target.isAlive())
return;
if(!firing_range)
if (entity_team < 0 || entity_team>50 || entity_team == team_player) return;
if(aim==2)
{
if((target.lastVisTime() > lastvis_aim[index]))
{
float fov = CalculateFov(LPlayer, target);
if (fov < max)
{
max = fov;
tmp_aimentity = target.ptr;
}
}
else
{
if(aimentity==target.ptr)
{
aimentity=tmp_aimentity=lastaimentity=0;
}
}
}
else
{
float fov = CalculateFov(LPlayer, target);
if (fov < max)
{
max = fov;
tmp_aimentity = target.ptr;
}
}
lastvis_aim[index] = target.lastVisTime();
}
void DoActions(WinProcess& mem)
{
actions_t = true;
while (actions_t)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
while (g_Base!=0 && c_Base!=0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(300));
uint64_t LocalPlayer = mem.Read<uint64_t>(g_Base + OFFSET_LOCAL_ENT);
if (LocalPlayer == 0) continue;
Entity LPlayer = getEntity(mem, LocalPlayer);
team_player = LPlayer.getTeamId();
if (team_player < 0 || team_player>50)
{
continue;
}
uint64_t entitylist = g_Base + OFFSET_ENTITYLIST;
uint64_t baseent = mem.Read<uint64_t>(entitylist);
if (baseent == 0)
{
continue;
}
max = 999.0f;
tmp_spec = 0;
tmp_all_spec = 0;
tmp_aimentity = 0;
if(firing_range)
{
int c=0;
for (int i = 0; i < 9000; i++)
{
uint64_t centity = mem.Read<uint64_t>(entitylist + ((uint64_t)i << 5));
if (centity == 0) continue;
if (LocalPlayer == centity) continue;
Entity Target = getEntity(mem, centity);
if (!Target.isDummy())
{
continue;
}
ProcessPlayer(mem, LPlayer, Target, entitylist, c);
c++;
}
}
else
{
for (int i = 0; i < toRead; i++)
{
uint64_t centity = mem.Read<uint64_t>(entitylist + ((uint64_t)i << 5));
if (centity == 0) continue;
if (LocalPlayer == centity) continue;
Entity Target = getEntity(mem, centity);
if (!Target.isPlayer())
{
continue;
}
ProcessPlayer(mem, LPlayer, Target, entitylist, i);
}
}
spectators = tmp_spec;
allied_spectators = tmp_all_spec;
if(!lock)
aimentity = tmp_aimentity;
else
aimentity = lastaimentity;
}
}
actions_t = false;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
player players[100];
static void EspLoop(WinProcess& mem)
{
esp_t = true;
while(esp_t)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
while(g_Base!=0 && c_Base!=0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (esp)
{
valid = false;
switch (safe_level)
{
case 1:
if (spectators > 0)
{
next = true;
while(next && g_Base!=0 && c_Base!=0 && esp)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
continue;
}
break;
case 2:
if (spectators+allied_spectators > 0)
{
next = true;
while(next && g_Base!=0 && c_Base!=0 && esp)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
continue;
}
break;
default:
break;
}
uint64_t LocalPlayer = mem.Read<uint64_t>(g_Base + OFFSET_LOCAL_ENT);
if (LocalPlayer == 0)
{
next = true;
while(next && g_Base!=0 && c_Base!=0 && esp)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
continue;
}
Entity LPlayer = getEntity(mem, LocalPlayer);
int team_player = LPlayer.getTeamId();
if (team_player < 0 || team_player>50)
{
next = true;
while(next && g_Base!=0 && c_Base!=0 && esp)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
continue;
}
Vector LocalPlayerPosition = LPlayer.getPosition();
uint64_t viewRenderer = mem.Read<uint64_t>(g_Base + OFFSET_RENDER);
uint64_t viewMatrix = mem.Read<uint64_t>(viewRenderer + OFFSET_MATRIX);
Matrix m = mem.Read<Matrix>(viewMatrix);
uint64_t entitylist = g_Base + OFFSET_ENTITYLIST;
memset(players,0,sizeof(players));
if(firing_range)
{
int c=0;
for (int i = 0; i < 9000; i++)
{
uint64_t centity = mem.Read<uint64_t>( entitylist + ((uint64_t)i << 5));
if (centity == 0)
{
continue;
}
if (LocalPlayer == centity)
{
continue;
}
Entity Target = getEntity(mem, centity);
if (!Target.isDummy())
{
continue;
}
if (!Target.isAlive())
{
continue;
}
int entity_team = Target.getTeamId();
Vector EntityPosition = Target.getPosition();
float dist = LocalPlayerPosition.DistTo(EntityPosition);
if (dist > max_dist || dist < 50.0f)
{
continue;
}
Vector bs = Vector();
WorldToScreen(EntityPosition, m.matrix, 1920, 1080, bs);
if (bs.x > 0 && bs.y > 0)
{
Vector hs = Vector();
Vector HeadPosition = Target.getBonePosition(mem, 8);
WorldToScreen(HeadPosition, m.matrix, 1920, 1080, hs);
float height = abs(abs(hs.y) - abs(bs.y));
float width = height / 2.0f;
float boxMiddle = bs.x - (width / 2.0f);
int health = Target.getHealth();
int shield = Target.getShield();
players[c] =
{
dist,
entity_team,
boxMiddle,
hs.y,
width,
height,
bs.x,
bs.y,
0,
(Target.lastVisTime() > lastvis_esp[c]),
health,
shield
};
lastvis_esp[c] = Target.lastVisTime();
valid = true;
c++;
}
}
}
else
{
for (int i = 0; i < toRead; i++)
{
uint64_t centity = mem.Read<uint64_t>( entitylist + ((uint64_t)i << 5));
if (centity == 0)
{
continue;
}
if (LocalPlayer == centity)
{
continue;
}
Entity Target = getEntity(mem, centity);
if (!Target.isPlayer())
{
continue;
}
if (!Target.isAlive())
{
continue;
}
int entity_team = Target.getTeamId();
if (entity_team < 0 || entity_team>50 || entity_team == team_player)
{
continue;
}
Vector EntityPosition = Target.getPosition();
float dist = LocalPlayerPosition.DistTo(EntityPosition);
if (dist > max_dist || dist < 50.0f)
{
continue;
}
Vector bs = Vector();
WorldToScreen(EntityPosition, m.matrix, 1920, 1080, bs);
if (bs.x > 0 && bs.y > 0)
{
Vector hs = Vector();
Vector HeadPosition = Target.getBonePosition(mem, 8);
WorldToScreen(HeadPosition, m.matrix, 1920, 1080, hs);
float height = abs(abs(hs.y) - abs(bs.y));
float width = height / 2.0f;
float boxMiddle = bs.x - (width / 2.0f);
int health = Target.getHealth();
int shield = Target.getShield();
players[i] =
{
dist,
entity_team,
boxMiddle,
hs.y,
width,
height,
bs.x,
bs.y,
Target.isKnocked(),
(Target.lastVisTime() > lastvis_esp[i]),
health,
shield
};
lastvis_esp[i] = Target.lastVisTime();
valid = true;
}
}
}
next = true;
while(next && g_Base!=0 && c_Base!=0 && esp)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
}
}
esp_t = false;
}
static void AimbotLoop(WinProcess& mem)
{
aim_t = true;
while (aim_t)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
while (g_Base!=0 && c_Base!=0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (aim>0)
{
switch (safe_level)
{
case 1:
if (spectators > 0)
{
continue;
}
break;
case 2:
if (spectators+allied_spectators > 0)
{
continue;
}
break;
default:
break;
}
if (aimentity == 0 || !aiming)
{
lock=false;
lastaimentity=0;
continue;
}
lock=true;
lastaimentity = aimentity;
uint64_t LocalPlayer = mem.Read<uint64_t>(g_Base + OFFSET_LOCAL_ENT);
if (LocalPlayer == 0) continue;
Entity LPlayer = getEntity(mem, LocalPlayer);
QAngle Angles = CalculateBestBoneAim(mem, LPlayer, aimentity, s_FOV);
if (Angles.x == 0 && Angles.y == 0)
{
lock=false;
lastaimentity=0;
continue;
}
LPlayer.SetViewAngles(mem, Angles);
}
}
}
aim_t = false;
}
static void set_vars(WinProcess& mem, uint64_t add_addr)
{
printf("Reading client vars...\n");
std::this_thread::sleep_for(std::chrono::milliseconds(50));
//Get addresses of client vars
uint64_t spec_addr = mem.Read<uint64_t>(add_addr);
uint64_t all_spec_addr = mem.Read<uint64_t>(add_addr + sizeof(uint64_t));
uint64_t aim_addr = mem.Read<uint64_t>(add_addr + sizeof(uint64_t)*2);
uint64_t esp_addr = mem.Read<uint64_t>(add_addr + sizeof(uint64_t)*3);
uint64_t safe_lev_addr = mem.Read<uint64_t>(add_addr + sizeof(uint64_t)*4);
uint64_t aiming_addr = mem.Read<uint64_t>(add_addr + sizeof(uint64_t)*5);
uint64_t g_Base_addr = mem.Read<uint64_t>(add_addr + sizeof(uint64_t)*6);
uint64_t next_addr = mem.Read<uint64_t>(add_addr + sizeof(uint64_t)*7);
uint64_t player_addr = mem.Read<uint64_t>(add_addr + sizeof(uint64_t)*8);
uint64_t valid_addr = mem.Read<uint64_t>(add_addr + sizeof(uint64_t)*9);
uint64_t max_dist_addr = mem.Read<uint64_t>(add_addr + sizeof(uint64_t)*10);
uint64_t item_glow_addr = mem.Read<uint64_t>(add_addr + sizeof(uint64_t)*11);
if(mem.Read<int>(spec_addr)!=1)
{
printf("Incorrect values read. Restart the client or check if the offset is correct. Quitting.\n");
active = false;
return;
}
vars_t = true;
while(vars_t)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if(c_Base!=0 && g_Base!=0)
printf("\nReady\n");
while(c_Base!=0 && g_Base!=0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
mem.Write<int>(spec_addr, spectators);
mem.Write<int>(all_spec_addr, allied_spectators);
mem.Write<uint64_t>(g_Base_addr, g_Base);
aim = mem.Read<int>(aim_addr);
esp = mem.Read<bool>(esp_addr);
safe_level = mem.Read<int>(safe_lev_addr);
aiming = mem.Read<bool>(aiming_addr);
max_dist = mem.Read<float>(max_dist_addr);
item_glow = mem.Read<bool>(item_glow_addr);
if(esp && next)
{
if(valid)
mem.WriteMem<player>(player_addr, players, sizeof(players));
mem.Write<bool>(valid_addr, valid);
mem.Write<bool>(next_addr, true); //next
while (mem.Read<bool>(next_addr) && g_Base!=0 && c_Base!=0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
next = false;
}
}
}
vars_t = false;
}
static void item_glow_t(WinProcess& mem)
{
item_t = true;
while(item_t)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
int k = 0;
while(g_Base!=0 && c_Base!=0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
uint64_t entitylist = g_Base + OFFSET_ENTITYLIST;
if (item_glow)
{
for (int i = 0; i < 10000; i++)
{
uint64_t centity = mem.Read<uint64_t>(entitylist + ((uint64_t)i << 5));
if (centity == 0) continue;
Item item = getItem(mem, centity);
if(item.isItem() && !item.isGlowing())
{
item.enableGlow(mem);
}
}
k=1;
std::this_thread::sleep_for(std::chrono::milliseconds(600));
}
else
{
if(k==1)
{
for (int i = 0; i < 10000; i++)
{
uint64_t centity = mem.Read<uint64_t>(entitylist + ((uint64_t)i << 5));
if (centity == 0) continue;
Item item = getItem(mem, centity);
if(item.isItem() && item.isGlowing())
{
item.disableGlow(mem);
}
}
k=0;
}
}
}
}
item_t = false;
}
__attribute__((constructor))
static void init()
{
FILE* out = stdout;
const char* cl_proc = "client.exe";
const char* ap_proc = "r5apex.exe";
pid_t pid;
#if (LMODE() == MODE_EXTERNAL())
FILE* pipe = popen("pidof qemu-system-x86_64", "r");
fscanf(pipe, "%d", &pid);
pclose(pipe);
#else
out = fopen("/tmp/testr.txt", "w");
pid = getpid();
#endif
fprintf(out, "Using Mode: %s\n", TOSTRING(LMODE));
dfile = out;
try
{
printf("\nStarting client context...\n");
WinContext ctx_client(pid);
printf("\nStarting apex context...\n");
WinContext ctx_apex(pid);
printf("\nStarting refresh process list context...\n");
WinContext ctx_refresh(pid);
printf("\n");
bool apex_found = false;
bool client_found = false;
//Client "add" offset
uint64_t add_off = 0xBA80;
while(active)
{
if(!apex_found)
{
aim_t = false;
esp_t = false;
actions_t = false;
item_t = false;
std::this_thread::sleep_for(std::chrono::seconds(1));
printf("Searching apex process...\n");
ctx_apex.processList.Refresh();
for (auto& i : ctx_apex.processList)
{
if (!strcasecmp(ap_proc, i.proc.name))
{
PEB peb = i.GetPeb();
short magic = i.Read<short>(peb.ImageBaseAddress);
g_Base = peb.ImageBaseAddress;
if(g_Base!=0)
{
apex_found = true;
fprintf(out, "\nApex found %lx:\t%s\n", i.proc.pid, i.proc.name);
fprintf(out, "\tBase:\t%lx\tMagic:\t%hx (valid: %hhx)\n", peb.ImageBaseAddress, magic, (char)(magic == IMAGE_DOS_SIGNATURE));
std::thread aimbot(AimbotLoop, std::ref(i));
std::thread esp_th(EspLoop, std::ref(i));
std::thread actions(DoActions, std::ref(i));
std::thread itemglow(item_glow_t, std::ref(i));
aimbot.detach();
esp_th.detach();
actions.detach();
itemglow.detach();
}
}
}
}
if(!client_found)
{
vars_t = false;
std::this_thread::sleep_for(std::chrono::seconds(1));
printf("Searching client process...\n");
ctx_client.processList.Refresh();
for (auto& i : ctx_client.processList)
{
if (!strcasecmp(cl_proc, i.proc.name))
{
PEB peb = i.GetPeb();
short magic = i.Read<short>(peb.ImageBaseAddress);
c_Base = peb.ImageBaseAddress;
if(c_Base!=0)
{
client_found = true;
fprintf(out, "\nClient found %lx:\t%s\n", i.proc.pid, i.proc.name);
fprintf(out, "\tBase:\t%lx\tMagic:\t%hx (valid: %hhx)\n", peb.ImageBaseAddress, magic, (char)(magic == IMAGE_DOS_SIGNATURE));
std::thread vars(set_vars, std::ref(i), c_Base + add_off);
vars.detach();
}
}
}
}
if(apex_found || client_found)
{
apex_found = false;
client_found = false;
std::this_thread::sleep_for(std::chrono::seconds(1));
ctx_refresh.processList.Refresh();
for (auto& i : ctx_refresh.processList)
{
if (!strcasecmp(cl_proc, i.proc.name))
{
PEB peb = i.GetPeb();
if(peb.ImageBaseAddress != 0)
{
if(vars_t)
client_found = true;
}
}
if (!strcasecmp(ap_proc, i.proc.name))
{
PEB peb = i.GetPeb();
if(peb.ImageBaseAddress != 0)
{
if(actions_t)
apex_found = true;
}
}
}
if(!apex_found && !client_found)
{
g_Base = 0;
c_Base = 0;
active = false;
}
else
{
if(!apex_found)
{
g_Base = 0;
}
if(!client_found)
{
c_Base = 0;
}
}
}
}
} catch (VMException& e)
{
fprintf(out, "Initialization error: %d\n", e.value);
}
fclose(out);
}
int main()
{
return 0;
}

@ -0,0 +1,33 @@
#define OFFSET_ENTITYLIST 0x18b9a98
#define OFFSET_LOCAL_ENT 0x1c684b8 //LocalPlayer
#define OFFSET_TEAM 0x430
#define OFFSET_HEALTH 0x420
#define OFFSET_NAME 0x561
#define OFFSET_SIG_NAME 0x558
#define OFFSET_SHIELD 0x170
#define OFFSET_ABS_VELOCITY 0x140 //m_vecAbsVelocity
#define OFFSET_VISIBLE_TIME 0x1A6C
#define OFFSET_LIFE_STATE 0x770 //>0 = dead
#define OFFSET_BLEED_OUT_STATE 0x2670 //>0 = knocked
#define OFFSET_ORIGIN 0x14c //m_vecAbsOrigin
#define OFFSET_BONES 0xF18 //m_bConstrainBetweenEndpoints
#define OFFSET_AIMPUNCH 0x23c8 //m_currentFrameLocalPlayer.m_vecPunchWeapon_Angle
#define OFFSET_CAMERAPOS 0x1E6C
#define OFFSET_VIEWANGLES 0x24A0
#define OFFSET_BREATH_ANGLES OFFSET_VIEWANGLES - 0x10
#define OFFSET_OBSERVER_MODE 0x3304
#define OFFSET_OBSERVING_TARGET 0x3308
#define OFFSET_MATRIX 0x1b3bd0
#define OFFSET_RENDER 0x40deec8
#define OFFSET_WEAPON 0x1a0c //m_latestPrimaryWeapons
#define OFFSET_BULLET_SPEED 0x1e08
#define OFFSET_BULLET_SCALE 0x1e10
#define OFFSET_ITEM_GLOW 0x290
#define OFFSET_GLOW_ENABLE 0x330 //7 = enabled
#define OFFSET_GLOW_THROUGH_WALLS 0x340 //2 = enabled

@ -0,0 +1,64 @@
#include <cmath>
#include "Game.h"
struct PredictCtx
{
Vector StartPos;
Vector TargetPos;
Vector TargetVel;
float BulletSpeed;
float BulletGravity;
Vector2D AimAngles;
};
Vector ExtrapolatePos(const PredictCtx& Ctx, float Time)
{
return Ctx.TargetPos + (Ctx.TargetVel * Time);
}
bool OptimalPitch(const PredictCtx& Ctx, const Vector2D& Dir2D, float* OutPitch)
{
float Vel = Ctx.BulletSpeed, Grav = Ctx.BulletGravity, DirX = Dir2D.x, DirY = Dir2D.y;
float Root = Vel * Vel * Vel * Vel - Grav * (Grav * DirX * DirX + 2.f * DirY * Vel * Vel);
if (Root >= 0.f) { *OutPitch = atanf((Vel * Vel - sqrt(Root)) / (Grav * DirX)); return true; }
return false;
}
bool SolveTrajectory(PredictCtx& Ctx, const Vector& ExtrPos, float* TravelTime)
{
Vector Dir = ExtrPos - Ctx.StartPos;
Vector2D Dir2D = { sqrtf(Dir.x * Dir.x + Dir.y * Dir.y), Dir.z };
float CurPitch;
if (!OptimalPitch(Ctx, Dir2D, &CurPitch))
{
return false;
}
*TravelTime = Dir2D.x / (cosf(CurPitch) * Ctx.BulletSpeed);
Ctx.AimAngles.y = atan2f(Dir.y, Dir.x);
Ctx.AimAngles.x = CurPitch;
return true;
}
bool BulletPredict(PredictCtx& Ctx)
{
float MAX_TIME = 1.f, TIME_STEP = (1.f / 256.f);
for (float CurrentTime = 0.f; CurrentTime <= MAX_TIME; CurrentTime += TIME_STEP)
{
float TravelTime;
Vector ExtrPos = ExtrapolatePos(Ctx, CurrentTime);
if (!SolveTrajectory(Ctx, ExtrPos, &TravelTime))
{
return false;
}
if (TravelTime < CurrentTime)
{
Ctx.AimAngles = { -RAD2DEG(Ctx.AimAngles.x), RAD2DEG(Ctx.AimAngles.y) };
return true;
}
}
return false;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29403.142
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Client", "Client\Client.vcxproj", "{9BF6CD05-63DA-49CF-905E-B82F5F24AC6E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9BF6CD05-63DA-49CF-905E-B82F5F24AC6E}.Debug|x64.ActiveCfg = Debug|x64
{9BF6CD05-63DA-49CF-905E-B82F5F24AC6E}.Debug|x64.Build.0 = Debug|x64
{9BF6CD05-63DA-49CF-905E-B82F5F24AC6E}.Release|x64.ActiveCfg = Release|x64
{9BF6CD05-63DA-49CF-905E-B82F5F24AC6E}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D6542325-B9BC-4057-A6CD-43137A5535C1}
EndGlobalSection
EndGlobal

@ -0,0 +1,60 @@
// Script di risorse generato con Microsoft Visual C++.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generato dalla risorsa TEXTINCLUDE 2.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Risorse di Italiano (Italia)
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE 16, 1
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // Risorse di Italiano (Italia)
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generato dalla risorsa TEXTINCLUDE 3.
//
/////////////////////////////////////////////////////////////////////////////
#endif // non APSTUDIO_INVOKED

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{9BF6CD05-63DA-49CF-905E-B82F5F24AC6E}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>Client</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>Client</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<UseOfMfc>false</UseOfMfc>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<LibraryPath>$(DXSDK_DIR)Lib\x64;$(LibraryPath)</LibraryPath>
<IncludePath>$(DXSDK_DIR)Include;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(DXSDK_DIR)Include;$(IncludePath)</IncludePath>
<LibraryPath>$(DXSDK_DIR)Lib\x64;$(LibraryPath)</LibraryPath>
<TargetName>client</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<WholeProgramOptimization>true</WholeProgramOptimization>
<RemoveUnreferencedCodeData>false</RemoveUnreferencedCodeData>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
<AdditionalDependencies>d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="DirectX.cpp" />
<ClCompile Include="overlay.cpp" />
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="DirectX.h" />
<ClInclude Include="main.h" />
<ClInclude Include="overlay.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Client.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Headers">
<UniqueIdentifier>{09a8a2aa-6277-49bc-bb28-4446ac81fb47}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="DirectX.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="overlay.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="DirectX.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="overlay.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="main.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Client.rc" />
</ItemGroup>
</Project>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

@ -0,0 +1,85 @@
#include "DirectX.h"
bool Direct::D3DInit(HWND hwnd,Direct& result)
{
Direct res = Direct();
if(FAILED(Direct3DCreate9Ex(D3D_SDK_VERSION, &res.dx_Object)))
return false;
res.dx_Params.hDeviceWindow = hwnd;
res.dx_Params.MultiSampleQuality = D3DMULTISAMPLE_NONE;
res.dx_Params.SwapEffect = D3DSWAPEFFECT_DISCARD;
res.dx_Params.BackBufferCount = 1;
res.dx_Params.BackBufferFormat = D3DFMT_A8R8G8B8;
res.dx_Params.BackBufferWidth = 0;
res.dx_Params.BackBufferHeight = 0;
res.dx_Params.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
res.dx_Params.Windowed = true;
if(FAILED(res.dx_Object->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &res.dx_Params, NULL, &res.dx_Device)))
return false;
D3DXCreateLine(res.dx_Device, &res.dx_line);
if (FAILED(D3DXCreateFontA(res.dx_Device, 13, 0, 400, 1, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, "Courier", &res.dx_font))) {
return false;
}
result = res;
return true;
}
void Direct::D3DShutdown()
{
if(dx_Device != NULL)
dx_Device->Release();
dx_Device = NULL;
if(dx_Object != NULL)
dx_Object->Release();
dx_Object = NULL;
}
void Direct::Fill(int x, int y, int w, int h, int r, int g, int b, int a)
{
D3DCOLOR col = D3DCOLOR_ARGB(a,r,g,b);
D3DRECT rec = { x, y, x+w, y+h };
dx_Device->Clear(1, &rec, D3DCLEAR_TARGET, col, 0, 0);
}
void Direct::DrawBox(int x,int y,int x2,int y2, int r, int g, int b, int a)
{
Fill(x-1, y-1, x2+2, 1, r, g, b, a);
Fill(x-1, y, 1, y2-1, r, g, b, a);
Fill(x+x2, y, 1, y2-1, r, g, b, a);
Fill(x-1, y+y2-1, x2+2, 1, r, g, b, a);
}
void Direct::DrawBox2(int x, int y, int width, int height, int r, int g, int b, int a)
{
D3DCOLOR color = D3DCOLOR_ARGB(a, r, g, b);
D3DCOLOR clear = D3DCOLOR_ARGB(0, 0, 0, 0);
D3DRECT rec_paint = { x, y, x+ width, y+ height };
D3DRECT rec_clear = { x + 1, y + 1, x + width - 1, y + height - 1 };
dx_Device->Clear(1, &rec_paint, D3DCLEAR_TARGET, color, 0, 0);
dx_Device->Clear(1, &rec_clear, D3DCLEAR_TARGET, clear, 0, 0);
}
void Direct::DrawString(int x, int y,int a,int r,int g,int b, LPCWSTR text)
{
D3DCOLOR col = D3DCOLOR_ARGB(a, r, g, b);
RECT rect;
rect.left = x;
rect.top = y;
rect.right = x+wcslen(text) * 10;
rect.bottom = y+30;
dx_font->DrawTextW(NULL, text, -1, &rect, DT_LEFT, col);
}
void Direct::DrawLine(float x, float y, float xx, float yy, int a,int r,int g,int b) {
D3DXVECTOR2 line[2];
dx_line->SetWidth(1);
line[0] = D3DXVECTOR2(x, y);
line[1] = D3DXVECTOR2(xx, yy);
dx_line->Draw(line, 2, D3DCOLOR_ARGB(a, r, g, b));
}

@ -0,0 +1,24 @@
#pragma once
#include <d3d9.h>
#pragma comment(lib, "d3d9.lib")
#include <d3dx9.h>
#pragma comment(lib, "d3dx9.lib")
class Direct
{
public:
IDirect3D9Ex* dx_Object;
IDirect3DDevice9Ex* dx_Device;
D3DPRESENT_PARAMETERS dx_Params;
LPD3DXLINE dx_line;
LPD3DXFONT dx_font;
static bool D3DInit(HWND hwnd,Direct& result);
void D3DShutdown();
void Fill(int x, int y, int w, int h, int r, int g, int b, int a);
void DrawBox(int x,int y,int x2,int y2, int r, int g, int b, int a);
void DrawBox2(int x, int y, int width, int height, int r, int g, int b, int a);
void DrawString(int x, int y, int a, int r, int g, int b, LPCWSTR text);
void DrawLine(float x, float y, float xx, float yy, int a, int r, int g, int b);
};

@ -0,0 +1,261 @@
#include "main.h"
typedef struct player
{
float dist = 0;
int entity_team = 0;
float boxMiddle = 0;
float h_y = 0;
float width = 0;
float height = 0;
float b_x = 0;
float b_y = 0;
bool knocked = false;
bool visible = false;
int health = 0;
int shield = 0;
}player;
bool use_nvidia = true;
bool active = true;
int spectators = 1; //write
int allied_spectators = 1; //write
int aim = 0; //read
bool esp = false; //read
int safe_level = 0; //read
bool item_glow = false;
bool aiming = false; //read
uint64_t g_Base = 0; //write
float max_dist = 200.0f*40.0f; //read
bool valid = false; //write
bool next = false; //read write
uint64_t add[12];
bool k_f5 = 0;
bool k_f6 = 0;
bool k_f7 = 0;
bool k_f8 = 0;
bool IsKeyDown(int vk)
{
return (GetAsyncKeyState(vk) & 0x8000) != 0;
}
player players[100];
void render(void* ovv)
{
next = false;
if (g_Base != 0 && esp)
{
memset(players, 0, sizeof(players));
Overlay* ov = (Overlay*)ovv;
Direct dx = ov->CurrentDirectX;
while (!next && esp)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
if (next && valid)
{
for (int i = 0; i < 100; i++)
{
if (players[i].width > 0)
{
std::wstring distance = std::to_wstring(players[i].dist / 39.62);
distance = distance.substr(0, distance.find('.')) + L"m(" + std::to_wstring(players[i].entity_team) + L")";
if (players[i].visible)
{
if (players[i].dist < 1600.0f)
dx.DrawBox2((int)players[i].boxMiddle, (int)players[i].h_y, (int)players[i].width, (int)players[i].height, 255, 0, 0, 255); //BOX
else
dx.DrawBox2((int)players[i].boxMiddle, (int)players[i].h_y, (int)players[i].width, (int)players[i].height, 255, 165, 0, 255); //BOX
}
else
{
dx.DrawBox2((int)players[i].boxMiddle, (int)players[i].h_y, (int)players[i].width, (int)players[i].height, 255, 255, 255, 255); //white if player not visible
}
dx.DrawLine((float)(ov->getWidth() / 2), (float)ov->getHeight(), players[i].b_x, players[i].b_y, 255, 0, 0, 255); //LINE FROM MIDDLE SCREEN
if (players[i].knocked)
dx.DrawString((int)players[i].boxMiddle, (int)(players[i].b_y + 1), 255, 255, 0, 0, distance.c_str()); //DISTANCE
else
dx.DrawString((int)players[i].boxMiddle, (int)(players[i].b_y + 1), 255, 0, 255, 0, distance.c_str()); //DISTANCE
int r = 0, g = 0, b = 0;
if (players[i].health > 75 && players[i].health <= 100)
{
r = 0;
g = 200;
b = 0;
}
else if (players[i].health > 50 && players[i].health <= 75)
{
r = 255;
g = 215;
b = 0;
}
else
{
r = 255;
g = 0;
b = 0;
}
dx.Fill((int)(players[i].b_x - (players[i].width / 2.0f) - 4), (int)(players[i].b_y - players[i].height), 3, (int)((players[i].height / 100.0f) * (float)players[i].health), r, g, b, 255);
if (players[i].shield > 75 && players[i].shield <= 125)
{
r = 0;
g = 200;
b = 0;
}
else if (players[i].shield > 50 && players[i].shield <= 75)
{
r = 255;
g = 215;
b = 0;
}
else
{
r = 255;
g = 0;
b = 0;
}
dx.Fill((int)(players[i].b_x + (players[i].width / 2.0f) + 1), (int)(players[i].b_y - players[i].height), 3, (int)((players[i].height / 100.0f) * (float)players[i].shield), r, g, b, 255);
}
}
}
}
}
int main(int argc, char** argv)
{
add[0] = (uintptr_t)&spectators;
add[1] = (uintptr_t)&allied_spectators;
add[2] = (uintptr_t)&aim;
add[3] = (uintptr_t)&esp;
add[4] = (uintptr_t)&safe_level;
add[5] = (uintptr_t)&aiming;
add[6] = (uintptr_t)&g_Base;
add[7] = (uintptr_t)&next;
add[8] = (uintptr_t)&players[0];
add[9] = (uintptr_t)&valid;
add[10] = (uintptr_t)&max_dist;
add[11] = (uintptr_t)&item_glow;
printf("add offset: 0x%I64x\n", (uint64_t)&add[0] - (uint64_t)GetModuleHandle(NULL));
Overlay ov1 = Overlay();
ov1.SetRender(render);
ov1.Start();
printf("Waiting for host process...\n");
while (spectators == 1)
{
if (IsKeyDown(VK_F4))
{
active = false;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
if(active)
printf("Ready\n");
while (active)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (IsKeyDown(VK_F4))
{
active = false;
}
if (IsKeyDown(VK_F5) && k_f5 == 0)
{
k_f5 = 1;
esp = !esp;
}
else if (!IsKeyDown(VK_F5) && k_f5 == 1)
{
k_f5 = 0;
}
if (IsKeyDown(VK_F6) && k_f6 == 0)
{
k_f6 = 1;
switch (aim)
{
case 0:
aim = 1;
break;
case 1:
aim = 2;
break;
case 2:
aim = 0;
break;
default:
break;
}
}
else if (!IsKeyDown(VK_F6) && k_f6 == 1)
{
k_f6 = 0;
}
if (IsKeyDown(VK_F7) && k_f7 == 0)
{
k_f7 = 1;
switch (safe_level)
{
case 0:
safe_level = 1;
break;
case 1:
safe_level = 2;
break;
case 2:
safe_level = 0;
break;
default:
break;
}
}
else if (!IsKeyDown(VK_F7) && k_f7 == 1)
{
k_f7 = 0;
}
if (IsKeyDown(VK_F8) && k_f8 == 0)
{
k_f8 = 1;
item_glow = !item_glow;
}
else if (!IsKeyDown(VK_F8) && k_f8 == 1)
{
k_f8 = 0;
}
if (IsKeyDown(VK_LEFT))
{
if (max_dist > 100.0f * 40.0f)
max_dist -= 50.0f * 40.0f;
std::this_thread::sleep_for(std::chrono::milliseconds(130));
}
if (IsKeyDown(VK_RIGHT))
{
if (max_dist < 800.0f * 40.0f)
max_dist += 50.0f * 40.0f;
std::this_thread::sleep_for(std::chrono::milliseconds(130));
}
if (IsKeyDown(VK_RBUTTON))
aiming = true;
else
aiming = false;
}
ov1.Clear();
if(!use_nvidia)
system("taskkill /F /T /IM overlay.exe"); //custom overlay process name
return 0;
}

@ -0,0 +1,11 @@
#pragma once
#include <windows.h>
#include <time.h>
#include <fstream>
#include <iostream>
#include <locale>
#include <codecvt>
#include "math.h"
#include "overlay.h"

@ -0,0 +1,215 @@
#include "overlay.h"
extern int aim;
extern bool esp;
extern bool item_glow;
extern bool active;
extern bool use_nvidia;
extern int safe_level;
extern int spectators;
extern int allied_spectators;
extern float max_dist;
int width;
int height;
LONG nv_default = WS_POPUP | WS_CLIPSIBLINGS;
LONG nv_default_in_game = nv_default | WS_DISABLED;
LONG nv_edit = nv_default_in_game | WS_VISIBLE;
LONG nv_ex_default = WS_EX_TOOLWINDOW;
LONG nv_ex_edit = nv_ex_default | WS_EX_LAYERED | WS_EX_TRANSPARENT;
static DWORD WINAPI StaticMessageStart(void* Param)
{
Overlay* ov = (Overlay*)Param;
ov->CreateOverlay();
return 0;
}
BOOL CALLBACK EnumWindowsCallback(HWND hwnd, LPARAM lParam)
{
wchar_t className[255] = L"";
GetClassName(hwnd, className, 255);
if (use_nvidia)
{
if (wcscmp(L"CEF-OSC-WIDGET", className) == 0) //Nvidia overlay
{
Process_Informations* proc = (Process_Informations*)lParam;
if (GetWindowLong(hwnd, GWL_STYLE) != nv_default && GetWindowLong(hwnd, GWL_STYLE) != nv_default_in_game)
return TRUE;
proc->overlayHWND = hwnd;
return TRUE;
}
}
else
{
if (wcscmp(L"overlay", className) == 0) //Custom overlay
{
Process_Informations* proc = (Process_Informations*)lParam;
proc->overlayHWND = hwnd;
return TRUE;
}
}
return TRUE;
}
DWORD Overlay::CreateOverlay()
{
EnumWindows(EnumWindowsCallback, (LPARAM)&proc);
Sleep(300);
if (proc.overlayHWND == 0)
{
printf("Can't find the overlay\n");
Sleep(1000);
exit(0);
}
HDC hDC = ::GetWindowDC(NULL);
width = ::GetDeviceCaps(hDC, HORZRES);
height = ::GetDeviceCaps(hDC, VERTRES);
if (!Direct::D3DInit(proc.overlayHWND, CurrentDirectX))
{
exit(0);
}
running = 1;
int rs = 255;
int gs = 255;
int bs = 255;
LPCWSTR txt = L"F5: ESP";
LPCWSTR txt2 = L"F6: AIM";
LPCWSTR txt3 = L"F8: ITEMS";
while (running)
{
if (CurrentDirectX.dx_Device != 0)
{
std::wstring title = L"title (" + std::to_wstring(spectators) + L" - " + std::to_wstring(allied_spectators) + L")";
std::wstring max_d = L"MAX DST: " + std::to_wstring((int)(max_dist / 40.0f));
try
{
HWND wnd = GetWindow(GetForegroundWindow(), GW_HWNDPREV);
if (use_nvidia)
{
if(GetWindowLong(proc.overlayHWND, GWL_STYLE) != nv_edit)
SetWindowLong(proc.overlayHWND, GWL_STYLE, nv_edit);
if(GetWindowLong(proc.overlayHWND, GWL_STYLE) != nv_ex_edit)
SetWindowLong(proc.overlayHWND, GWL_EXSTYLE, nv_ex_edit);
}
if (wnd != proc.overlayHWND)
{
SetWindowPos(proc.overlayHWND, wnd, 0, 0, 0, 0, SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE);
UpdateWindow(proc.overlayHWND);
}
CurrentDirectX.dx_Device->Clear(NULL, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, NULL);
CurrentDirectX.dx_Device->BeginScene();
switch (safe_level)
{
case 0:
rs = 255;
gs = 0;
bs = 0;
break;
case 1:
rs = 255;
gs = 215;
bs = 0;
break;
case 2:
rs = 0;
gs = 200;
bs = 0;
break;
default:
break;
}
CurrentDirectX.DrawString(10, 10, 255, rs, gs, bs, (LPCWSTR)title.c_str());
if (esp)
{
CurrentDirectX.DrawString(10, 25, 255, 0, 255, 0, txt); //green
}
else
{
CurrentDirectX.DrawString(10, 25, 255, 255, 0, 0, txt); //red
}
if (aim==2)
{
std::wstring v = L"F6: AIM (V)";
CurrentDirectX.DrawString(10, 38, 255, 0, 255, 0, (LPCWSTR)v.c_str()); //green
}
else if(aim==1)
{
CurrentDirectX.DrawString(10, 38, 255, 0, 255, 0, txt2); //green
}
else
{
CurrentDirectX.DrawString(10, 38, 255, 255, 0, 0, txt2); //red
}
if (item_glow)
{
CurrentDirectX.DrawString(10, 51, 255, 0, 255, 0, txt3); //green
}
else
{
CurrentDirectX.DrawString(10, 51, 255, 255, 0, 0, txt3); //red
}
CurrentDirectX.DrawString(10, 51, 255, 255, 215, 0, (LPCWSTR)max_d.c_str());
Render();
CurrentDirectX.dx_Device->EndScene();
CurrentDirectX.dx_Device->Present(NULL, NULL, NULL, NULL);
}
catch (...) {
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
return 0;
}
void Overlay::Start()
{
DWORD ThreadID;
CreateThread(NULL, 0, StaticMessageStart, (void*)this, 0, &ThreadID);
}
void Overlay::Render()
{
(*(RenderCallbacks))(this);
}
void Overlay::SetRender(RenderCallback v)
{
RenderCallbacks = v;
}
bool Overlay::isRunning()
{
return running;
}
void Overlay::Clear()
{
running = 0;
Sleep(50);
if (use_nvidia)
{
SetWindowLong(proc.overlayHWND, GWL_STYLE, nv_default);
SetWindowLong(proc.overlayHWND, GWL_EXSTYLE, nv_ex_default);
}
CurrentDirectX.D3DShutdown();
}
int Overlay::getWidth()
{
return width;
}
int Overlay::getHeight()
{
return height;
}

@ -0,0 +1,40 @@
#pragma once
#include <Windows.h>
#include <WinUser.h>
#include "DirectX.h"
#include <Dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
#include <stdlib.h>
#include <vector>
#include <chrono>
#include <cwchar>
#include <thread>
#include <string>
typedef void (*RenderCallback) (void* ov);
struct Process_Informations
{
HWND overlayHWND;
};
class Overlay
{
public:
void Start();
DWORD CreateOverlay();
void Render();
void Clear();
void SetRender(RenderCallback render);
bool isRunning();
int getWidth();
int getHeight();
Direct CurrentDirectX;
private:
bool running;
RenderCallback RenderCallbacks;
Process_Informations proc;
};

@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by LocalStrunder.rc
// Valori predefiniti successivi per i nuovi oggetti
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29519.87
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Overlay", "Overlay\Overlay.vcxproj", "{68C049A1-7EA4-45D2-942C-7710AF16B1FA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{68C049A1-7EA4-45D2-942C-7710AF16B1FA}.Debug|x64.ActiveCfg = Debug|x64
{68C049A1-7EA4-45D2-942C-7710AF16B1FA}.Debug|x64.Build.0 = Debug|x64
{68C049A1-7EA4-45D2-942C-7710AF16B1FA}.Release|x64.ActiveCfg = Release|x64
{68C049A1-7EA4-45D2-942C-7710AF16B1FA}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CA1CD6B1-E5B8-4031-A3BE-BCFCBAE43EEA}
EndGlobalSection
EndGlobal

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{68C049A1-7EA4-45D2-942C-7710AF16B1FA}</ProjectGuid>
<RootNamespace>Overlay</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>Overlay</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<TargetName>overlay</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>

@ -0,0 +1,48 @@
#include <Windows.h>
#include <chrono>
#include <Dwmapi.h>
#pragma comment(lib, "dwmapi.lib")
const MARGINS margins = { -1 ,-1, -1, -1 };
const wchar_t g_szClassName[] = L"overlay";
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(RGB(0,0,0));
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wc);
hwnd = CreateWindowEx(
WS_EX_LAYERED | WS_EX_TRANSPARENT,
g_szClassName,
g_szClassName,
WS_POPUP | WS_VISIBLE,
0, 0, 500, 500,
NULL, NULL, hInstance, NULL);
SetLayeredWindowAttributes(hwnd, RGB(0,0,0), 255, LWA_ALPHA);
DwmExtendFrameIntoClientArea(hwnd, &margins);
while (GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
exit(0);
return Msg.wParam;
}

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29519.87
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Client", "Client\Client\Client.vcxproj", "{9BF6CD05-63DA-49CF-905E-B82F5F24AC6E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Overlay", "Overlay\Overlay\Overlay.vcxproj", "{68C049A1-7EA4-45D2-942C-7710AF16B1FA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9BF6CD05-63DA-49CF-905E-B82F5F24AC6E}.Debug|x64.ActiveCfg = Debug|x64
{9BF6CD05-63DA-49CF-905E-B82F5F24AC6E}.Debug|x64.Build.0 = Debug|x64
{9BF6CD05-63DA-49CF-905E-B82F5F24AC6E}.Release|x64.ActiveCfg = Release|x64
{9BF6CD05-63DA-49CF-905E-B82F5F24AC6E}.Release|x64.Build.0 = Release|x64
{68C049A1-7EA4-45D2-942C-7710AF16B1FA}.Debug|x64.ActiveCfg = Debug|x64
{68C049A1-7EA4-45D2-942C-7710AF16B1FA}.Debug|x64.Build.0 = Debug|x64
{68C049A1-7EA4-45D2-942C-7710AF16B1FA}.Release|x64.ActiveCfg = Release|x64
{68C049A1-7EA4-45D2-942C-7710AF16B1FA}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CA1CD6B1-E5B8-4031-A3BE-BCFCBAE43EEA}
EndGlobalSection
EndGlobal

@ -0,0 +1,7 @@
#!/bin/sh
path="apex_dma/build"
if [ -d "$path" ]; then
cd "$path" && ninja;
else
cd vmread && meson "../$path" && cd "../$path" && ninja;
fi

File diff suppressed because it is too large Load Diff

@ -0,0 +1,8 @@
Copyright (c) 2018 A. B. (Heep042)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -0,0 +1,23 @@
obj-m += vmread.o
vmread-objs := kmem.o
MCFLAGS += -O3
ccflags-y += ${MCFLAGS}
CC += ${MCFLAGS}
KDIR := /lib/modules/$(shell uname -r)/build
KOUTPUT := $(PWD)/build/vmread_kmod
KOUTPUT_MAKEFILE := $(KOUTPUT)/Makefile
all: $(KOUTPUT_MAKEFILE)
make -C $(KDIR) M=$(KOUTPUT) src=$(PWD) modules
cp $(KOUTPUT)/vmread.ko $(KOUTPUT)/../vmread.ko
$(KOUTPUT):
mkdir -p "$@"
$(KOUTPUT_MAKEFILE): $(KOUTPUT)
touch "$@"
clean:
make -C $(KDIR) M=$(KOUTPUT) src=$(PWD) clean
$(shell rm $(KOUTPUT_MAKEFILE))
rmdir $(KOUTPUT)

@ -0,0 +1,46 @@
#ifndef DEFINITIONS_H
#define DEFINITIONS_H
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#include <stdio.h>
#include "processdata.h"
extern FILE* vmread_dfile;
#define MODE_EXTERNAL() 1
#define MODE_QEMU_INJECT() 2
#define MODE_DMA() 3
#define DMSG(...) fprintf(vmread_dfile ? vmread_dfile : stdout, __VA_ARGS__)
#define NMSG(...)
#define PASTE(A, B) A##B
#if (MVERBOSE >= 1)
#define MSG1 DMSG
#else
#define MSG1 NMSG
#endif
#if (MVERBOSE >= 2)
#define MSG2 DMSG
#else
#define MSG2 NMSG
#endif
#if (MVERBOSE >= 3)
#define MSG3 DMSG
#else
#define MSG3 NMSG
#endif
#if (MVERBOSE >= 4)
#define MSG4 DMSG
#else
#define MSG4 NMSG
#endif
#define MSG(LEVEL, ...) PASTE(MSG, LEVEL) (__VA_ARGS__)
#endif

@ -0,0 +1,18 @@
#!/bin/bash
BUILD_DIR=$1
if [[ -z $(lsmod | grep vmread ) ]]; then
echo loading vmread module
if [[ ! -f $BUILD_DIR/vmread.ko ]]; then
echo build vmread first!
exit
fi
sudo insmod $BUILD_DIR/vmread.ko
fi
echo "Running external mode..."
sudo ./build/example | tail -n 5 > read_external
echo "Running kernel mapped mode..."
sudo ./build/kmod_example | tail -n 5 > read_kmod
gnuplot perf_plot.p

@ -0,0 +1,305 @@
#ifndef HLAPI_H
#define HLAPI_H
/* A high level C++ wrapper for various memory functions */
#include "../wintools.h"
#include "../mem.h"
#include <stdexcept>
#include <string.h>
#include <vector>
#include <algorithm>
class VMException : public std::exception
{
public:
VMException(int status)
{
value = status;
}
int value;
};
template<typename T>
class WinListIterator
{
public:
WinListIterator(T* l)
{
list = l;
count = 0;
}
WinListIterator(T* l, size_t c)
{
list = l;
count = c;
}
auto& operator*()
{
return list->list[count];
}
WinListIterator& operator++(int c)
{
count += c;
return *this;
}
WinListIterator& operator++()
{
return operator++(1);
}
WinListIterator& operator--(int c)
{
count -= c;
return *this;
}
WinListIterator& operator--()
{
return operator--(1);
}
bool operator==(WinListIterator& rhs)
{
return count == rhs.count && list == rhs.list;
}
bool operator!=(WinListIterator& rhs)
{
return !operator==(rhs);
}
protected:
size_t count;
private:
T* list;
};
class WinExportIteratableList
{
public:
using iterator = WinListIterator<WinExportList>;
iterator begin();
iterator end();
size_t getSize();
private:
friend class WinListIterator<WinExportList>;
friend class WinDll;
class WinDll* windll;
WinExportList list;
};
class WinDll
{
public:
uint64_t GetProcAddress(const char* procName);
WinDll();
WinDll(const class WinProcess* p, WinModule& i);
WinDll(WinDll&& rhs);
WinDll(WinDll& rhs) = delete;
~WinDll();
auto& operator=(WinDll&& rhs)
{
info = rhs.info;
std::swap(exports.list, rhs.exports.list);
process = rhs.process;
proc = rhs.proc;
return *this;
}
WinModule info;
WinExportIteratableList exports;
const class WinProcess* process;
private:
WinProc proc;
friend class WinExportIteratableList;
void VerifyExportList();
};
class ModuleIteratableList
{
public:
using iterator = WinListIterator<ModuleIteratableList>;
ModuleIteratableList(bool k = false);
ModuleIteratableList(class WinProcess* p, bool k = false);
ModuleIteratableList(ModuleIteratableList&& rhs);
ModuleIteratableList(ModuleIteratableList& rhs) = delete;
~ModuleIteratableList();
ModuleIteratableList& operator=(ModuleIteratableList&& rhs) = default;
iterator begin();
iterator end();
size_t getSize();
void Verify();
void InvalidateList();
WinDll* GetModuleInfo(const char* moduleName);
private:
friend class WinListIterator<ModuleIteratableList>;
friend class WinProcess;
friend class WinProcessList;
class WinProcess* process;
bool kernel;
WinDll* list;
size_t size;
};
class WriteList
{
public:
WriteList(const WinProcess*);
~WriteList();
void Commit();
template<typename T>
void Write(uint64_t address, T& value)
{
writeList.push_back({(uint64_t)buffer.size(), address, sizeof(T)});
buffer.reserve(sizeof(T));
std::copy((char*)&value, (char*)&value + sizeof(T), std::back_inserter(buffer));
}
const WinCtx* ctx;
const WinProc* proc;
private:
std::vector<RWInfo> writeList;
std::vector<char> buffer;
};
class WinProcess
{
public:
[[deprecated("Please use ModuleIteratableList::GetModuleInfo")]]
WinDll* GetModuleInfo(const char* moduleName);
PEB GetPeb();
WinProcess();
WinProcess(const WinProc& p, const WinCtx* c);
WinProcess(WinProcess&& rhs);
WinProcess(WinProcess& rhs) = delete;
void UpdateKernelModuleProcess(const WinProc& p);
WinProcess& operator=(WinProcess&& rhs) noexcept;
ssize_t Read(uint64_t address, void* buffer, size_t sz);
ssize_t Write(uint64_t address, void* buffer, size_t sz);
void ReadMem(uint64_t address, uint64_t remote, int len)
{
VMemRead(&ctx->process, proc.dirBase, remote, address, len);
}
template<typename T>
T Read(uint64_t address)
{
T ret;
VMemRead(&ctx->process, proc.dirBase, (uint64_t)&ret, address, sizeof(T));
return ret;
}
template<typename T>
void Write(uint64_t address, const T& value)
{
VMemWrite(&ctx->process, proc.dirBase, (uint64_t)&value, address, sizeof(T));
}
template<typename T>
void WriteMem(uint64_t address, T value[], int len)
{
VMemWrite(&ctx->process, proc.dirBase, (uint64_t)value, address, len);
}
WinProc proc;
const WinCtx* ctx;
ModuleIteratableList modules;
protected:
friend class ModuleIteratableList;
friend class WriteList;
};
class WinProcessList
{
public:
using iterator = WinListIterator<WinProcessList>;
void Refresh();
WinProcess* FindProc(const char* name);
iterator begin();
iterator end();
WinProcessList();
WinProcessList(const WinCtx* pctx);
WinProcessList(WinProcessList&& rhs);
WinProcessList(WinProcessList& rhs) = delete;
~WinProcessList();
auto& operator=(WinProcessList rhs)
{
std::swap(plist, rhs.plist);
std::swap(list, rhs.list);
ctx = rhs.ctx;
return *this;
}
const WinCtx* ctx;
protected:
friend iterator;
WinProcList plist;
WinProcess* list;
void FreeProcessList();
};
class SystemModuleList
{
public:
ModuleIteratableList& Get(WinProcess* p)
{
proc.UpdateKernelModuleProcess(p ? p->proc : proc.ctx->initialProcess);
return proc.modules;
}
private:
friend class WinContext;
WinProcess proc;
};
class WinContext
{
public:
template<typename T>
T Read(uint64_t address)
{
T ret;
MemRead(&ctx.process, (uint64_t)&ret, address, sizeof(T));
return ret;
}
template<typename T>
void Write(uint64_t address, T& value)
{
MemWrite(&ctx.process, (uint64_t)&value, address, sizeof(T));
}
WinContext(pid_t pid)
{
int ret = InitializeContext(&ctx, pid);
if (ret)
throw VMException(ret);
processList = WinProcessList(&ctx);
systemModuleList.proc.ctx = &ctx;
}
~WinContext()
{
FreeContext(&ctx);
}
WinProcessList processList;
SystemModuleList systemModuleList;
WinCtx ctx;
};
#endif

@ -0,0 +1,27 @@
#ifndef POINTERS_H
#define POINTERS_H
#include "hlapi.h"
template<typename T, WinProcess*& P>
struct vptr
{
uint64_t addr;
T value;
vptr(uint64_t address)
{
Init(address);
}
inline void Init(uint64_t address)
{
addr = address;
}
inline T& operator* () {
value = P->Read<T>(addr);
return value;
}
};
#endif

@ -0,0 +1,68 @@
#include "hlapi.h"
WinExportIteratableList::iterator WinExportIteratableList::begin()
{
windll->VerifyExportList();
return iterator(&list);
}
WinExportIteratableList::iterator WinExportIteratableList::end()
{
windll->VerifyExportList();
return iterator(&list, list.size);
}
size_t WinExportIteratableList::getSize()
{
windll->VerifyExportList();
return list.size;
}
uint64_t WinDll::GetProcAddress(const char* procName)
{
VerifyExportList();
return ::FindProcAddress(exports.list, procName);
}
WinDll::WinDll()
{
process = nullptr;
exports.list.list = nullptr;
exports.list.size = 0;
exports.windll = this;
}
WinDll::WinDll(const WinProcess* p, WinModule& i)
: WinDll()
{
process = p;
info = i;
}
WinDll::WinDll(WinDll&& rhs)
{
info = rhs.info;
process = rhs.process;
proc = rhs.proc;
exports = rhs.exports;
exports.windll = this;
rhs.exports.list.list = nullptr;
rhs.exports.list.size = 0;
}
WinDll::~WinDll()
{
FreeExportList(exports.list);
}
void WinDll::VerifyExportList()
{
if (proc.dirBase != process->proc.dirBase) {
proc = process->proc;
FreeExportList(exports.list);
memset(&exports.list, 0, sizeof(exports.list));
}
if (!exports.list.list)
GenerateExportList(process->ctx, &proc, info.baseAddress, &exports.list);
}

@ -0,0 +1,153 @@
#include "hlapi.h"
ModuleIteratableList::ModuleIteratableList(bool k)
: process(nullptr), kernel(k), list(nullptr), size(0)
{
}
ModuleIteratableList::ModuleIteratableList(WinProcess* p, bool k)
: ModuleIteratableList(k)
{
process = p;
}
ModuleIteratableList::ModuleIteratableList(ModuleIteratableList&& rhs)
: process(rhs.process), kernel(rhs.kernel), list(rhs.list), size(rhs.size)
{
if (process->modules.process != process)
*(volatile bool*)nullptr = 0;
}
ModuleIteratableList::~ModuleIteratableList()
{
InvalidateList();
}
ModuleIteratableList::iterator ModuleIteratableList::begin()
{
Verify();
return iterator(this);
}
ModuleIteratableList::iterator ModuleIteratableList::end()
{
Verify();
return iterator(this, size);
}
size_t ModuleIteratableList::getSize()
{
Verify();
return size;
}
void ModuleIteratableList::Verify()
{
if (!list) {
WinModuleList ls = !kernel ? GenerateModuleList(process->ctx, &process->proc) : GenerateKernelModuleList(process->ctx);
list = new WinDll[ls.size];
size = ls.size;
for (size_t i = 0; i < size; i++)
list[i] = WinDll(process, ls.list[i]);
free(ls.list);
}
}
void ModuleIteratableList::InvalidateList()
{
if (list)
for (size_t i = 0; i < size; i++)
free(list[i].info.name);
delete[] list;
list = nullptr;
}
WinDll* ModuleIteratableList::GetModuleInfo(const char* moduleName)
{
Verify();
for (size_t i = 0; i < size; i++)
if (!strcmp(moduleName, list[i].info.name))
return list + i;
return nullptr;
}
WriteList::WriteList(const WinProcess* p)
{
ctx = p->ctx;
proc = &p->proc;
}
WriteList::~WriteList()
{
size_t sz = writeList.size();
for (size_t i = 0; i < sz; i++)
free((void*)writeList[i].local);
}
void WriteList::Commit()
{
size_t sz = writeList.size();
RWInfo* infos = writeList.data();
uint64_t bufmem = (uint64_t)buffer.data();
for (size_t i = 0; i < sz; i++)
infos[i].local += bufmem;
VMemWriteMul(&ctx->process, proc->dirBase, infos, sz);
writeList.clear();
buffer.clear();
}
WinDll* WinProcess::GetModuleInfo(const char* moduleName)
{
return modules.GetModuleInfo(moduleName);
}
PEB WinProcess::GetPeb()
{
return ::GetPeb(ctx, &proc);
}
WinProcess::WinProcess()
: ctx(nullptr), modules(this)
{
}
WinProcess::WinProcess(const WinProc& p, const WinCtx* c)
: proc(p), ctx(c), modules(this)
{
}
WinProcess::WinProcess(WinProcess&& rhs)
{
*this = std::move(rhs);
}
WinProcess& WinProcess::operator=(WinProcess&& rhs) noexcept
{
proc = rhs.proc;
ctx = rhs.ctx;
modules = std::move(rhs.modules);
modules.process = this;
return *this;
}
void WinProcess::UpdateKernelModuleProcess(const WinProc& p)
{
proc = p;
modules.kernel = true;
}
ssize_t WinProcess::Read(uint64_t address, void* buffer, size_t sz)
{
return VMemRead(&ctx->process, proc.dirBase, (uint64_t)buffer, address, sz);
}
ssize_t WinProcess::Write(uint64_t address, void* buffer, size_t sz)
{
return VMemWrite(&ctx->process, proc.dirBase, (uint64_t)buffer, address, sz);
}

@ -0,0 +1,67 @@
#include "hlapi.h"
WinProcessList::iterator WinProcessList::begin()
{
return iterator(this);
}
WinProcessList::iterator WinProcessList::end()
{
return iterator(this, plist.size);
}
void WinProcessList::Refresh()
{
FreeProcessList();
plist = GenerateProcessList(ctx);
delete[] list;
list = new WinProcess[plist.size];
for (size_t i = 0; i < plist.size; i++)
list[i] = WinProcess(plist.list[i], ctx);
}
WinProcess* WinProcessList::FindProc(const char* name)
{
if (!plist.list)
Refresh();
for (auto& i : *this)
if (!strcmp(name, i.proc.name))
return &i;
return nullptr;
}
WinProcessList::WinProcessList()
{
plist.list = nullptr;
plist.size = 0;
list = nullptr;
ctx = nullptr;
}
WinProcessList::WinProcessList(const WinCtx* pctx)
: WinProcessList()
{
ctx = pctx;
Refresh();
}
WinProcessList::WinProcessList(WinProcessList&& rhs)
{
ctx = rhs.ctx;
std::swap(plist, rhs.plist);
std::swap(list, rhs.list);
}
WinProcessList::~WinProcessList()
{
FreeProcessList();
delete[] list;
}
void WinProcessList::FreeProcessList()
{
::FreeProcessList(plist);
plist.list = nullptr;
}

@ -0,0 +1,15 @@
#!/bin/sh
cp build/libexample.so /tmp/libexample.so
sudo gdb -n -q -batch \
-ex "attach $(pidof qemu-system-x86_64)" \
-ex "set \$dlopen = (void*(*)(char*, int)) dlopen" \
-ex "set \$dlclose = (int(*)(void*)) dlclose" \
-ex "set \$dlerror = (char*(*)(void)) dlerror" \
-ex "set \$library = \$dlopen(\"/tmp/libexample.so\", 1)" \
-ex "p \$library ? \"Injection successful!\" : \"Injection failed!\"" \
-ex "call \$library ? \$dlclose(\$library) : \$dlerror()" \
-ex "detach" \
-ex "quit"

@ -0,0 +1,56 @@
#include "mem.h"
#include <string.h>
/* Implementation for direct memory reads, used when injected into the QEMU process */
extern uint64_t KFIXC;
extern uint64_t KFIXO;
uint64_t KFIXC = 0x80000000;
uint64_t KFIXO = 0x80000000;
#define KFIX2(x) ((x) < KFIXC ? (x) : ((x) - KFIXO))
ssize_t MemRead(const ProcessData* data, uint64_t localAddr, uint64_t remoteAddr, size_t len)
{
uint64_t remote = KFIX2(remoteAddr);
if (remote >= data->mapsSize - len)
return -1;
memcpy((void*)localAddr, (void*)(remote + data->mapsStart), len);
return len;
}
ssize_t MemReadMul(const ProcessData* data, RWInfo* rdata, size_t num)
{
ssize_t flen = 0;
size_t i;
for (i = 0; i < num; i++) {
uint64_t remote = KFIX2(rdata[i].remote);
if (remote >= data->mapsSize - rdata[i].size)
return -1;
memcpy((void*)rdata[i].local, (void*)(remote + data->mapsStart), rdata[i].size);
flen += rdata[i].size;
}
return flen;
}
ssize_t MemWrite(const ProcessData* data, uint64_t localAddr, uint64_t remoteAddr, size_t len)
{
uint64_t remote = KFIX2(remoteAddr);
if (remote >= data->mapsSize - len)
return -1;
memcpy((void*)(remote + data->mapsStart), (void*)localAddr, len);
return len;
}
ssize_t MemWriteMul(const ProcessData* data, RWInfo* wdata, size_t num)
{
ssize_t flen = 0;
size_t i;
for (i = 0; i < num; i++) {
uint64_t remote = KFIX2(wdata[i].remote);
if (remote >= data->mapsSize - wdata[i].size)
return -1;
memcpy((void*)(remote + data->mapsStart), (void*)wdata[i].local, wdata[i].size);
flen += wdata[i].size;
}
return flen;
}

@ -0,0 +1,174 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/printk.h>
#include <linux/uaccess.h>
#include <linux/kallsyms.h>
#include "kmem.h"
MODULE_DESCRIPTION("vmread in-kernel helper used to accelerate memory operations");
MODULE_AUTHOR("Heep");
MODULE_LICENSE("GPL");
static int vmreadinit(void);
static void vmreadexit(void);
static void vmmap(ProcessData* data);
static long unlocked_ioctl(struct file* filp, unsigned int cmd, unsigned long argp);
module_init(vmreadinit);
module_exit(vmreadexit);
#define KSYMDEC(x) static typeof(&x) _##x = NULL
#define KSYM(x) _##x
#define KSYMDEF(x) _##x = (typeof(&x))kallsyms_lookup_name(#x)
KSYMDEC(insert_vm_struct);
KSYMDEC(vm_area_alloc);
KSYMDEC(vm_area_free);
static const struct file_operations fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = unlocked_ioctl
};
static int vmreadinit(void)
{
proc_create("vmread", 0, 0, &fops);
KSYMDEF(insert_vm_struct);
KSYMDEF(vm_area_alloc);
KSYMDEF(vm_area_free);
printk("vmread: initialized\n");
return 0;
}
static void vmreadexit(void)
{
remove_proc_entry("vmread", NULL);
printk("vmread: uninitialized\n");
}
static long unlocked_ioctl(struct file* filp, unsigned int cmd, unsigned long argp)
{
void* __user userArgs;
ProcessData kernelArgs;
userArgs = (void* __user)argp;
switch (cmd) {
case VMREAD_IOCTL_MAPVMMEM:
if (copy_from_user(&kernelArgs, userArgs, sizeof(kernelArgs)))
return -EFAULT;
vmmap(&kernelArgs);
if (copy_to_user(userArgs, &kernelArgs, sizeof(kernelArgs)))
return -EFAULT;
break;
}
return 0;
}
static void map_part_of_vm(struct vm_area_struct* vma, uint64_t targetAddr, uint64_t size, uint64_t pfn)
{
uint64_t end = targetAddr + PAGE_ALIGN(size);
if (targetAddr >= end)
return;
remap_pfn_range(vma, targetAddr, pfn, size, PAGE_SHARED);
}
static uint64_t map_task_pages(struct task_struct* task, uint64_t addr, uint64_t size, int hugePages)
{
struct mm_struct* mm = task->mm;
uint64_t ret = 0;
uint64_t pageSize = 0x1000;
uint64_t pageMul = hugePages ? 512 : 1;
int locked = 1;
uint64_t nrPages = size / pageSize;
struct page** pages = NULL;
long gotPages = 0;
size_t i;
struct vm_area_struct* vma, *prevVma;
uint64_t origPdp = addr >> 39;
uint64_t targetPdp = origPdp - 0x20;
uint64_t targetAddr = (addr & ~(origPdp << 39)) | (targetPdp << 39);
vm_flags_t vmFlags = VM_READ | VM_WRITE | VM_SHARED;
if (!mm || !_vm_area_free || !_vm_area_alloc || !_insert_vm_struct)
return 0;
pages = (struct page**)vmalloc(sizeof(struct page*) * nrPages);
printk("vmread: checking 0x%llx pages\n", nrPages);
down_write(&mm->mmap_sem);
gotPages = get_user_pages_remote(task, mm, addr, nrPages, FOLL_GET, pages, NULL, &locked);
printk("vmread: got 0x%lx pages\n", gotPages);
if (gotPages > 0) {
/* this should never occur in sane conditions, but better safe than deadlock */
if (current->mm != mm)
down_write(&current->mm->mmap_sem);
vma = _vm_area_alloc(current->mm);
prevVma = current->mm->mmap;
if (!vma)
goto cleanup;
if (!prevVma) {
_vm_area_free(vma);
goto cleanup;
}
vma->vm_start = targetAddr;
vma->vm_end = targetAddr + size;
vma->vm_flags = vmFlags;
vma->vm_page_prot = vm_get_page_prot(vmFlags);
vma->vm_pgoff = 0;
_insert_vm_struct(current->mm, vma);
for (i = 0; i < gotPages; i += pageMul)
map_part_of_vm(vma, targetAddr + pageSize * i, pageSize * pageMul, page_to_pfn(pages[i]));
ret = targetAddr;
cleanup:
while (gotPages-- > 0)
put_page(pages[gotPages]);
if (current->mm != mm)
up_write(&current->mm->mmap_sem);
}
if (locked)
up_write(&mm->mmap_sem);
return ret;
}
static void vmmap(ProcessData* data)
{
struct task_struct* task = NULL;
uint64_t addr = data->mapsStart;
task = pid_task(find_vpid(data->pid), PIDTYPE_PID);
if (!task)
return;
addr = map_task_pages(task, data->mapsStart, data->mapsSize, 0);
if (addr) {
data->mapsStart = addr;
data->pid = task_pid_nr(current);
printk("vmread: mapping successful!\n");
}
}

@ -0,0 +1,19 @@
#ifndef KMEM_H
#define KMEM_H
#include <linux/ioctl.h>
#include <linux/types.h>
#include "processdata.h"
#ifdef __cplusplus
extern "C" {
#endif
#define VMREAD_IOCTL_MAGIC 0x42
#define VMREAD_IOCTL_MAPVMMEM _IOWR(VMREAD_IOCTL_MAGIC, 0, ProcessData)
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,346 @@
#include "mem.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#ifndef NO_ASSERTS
#include <assert.h>
#endif
#if (LMODE() == MODE_EXTERNAL() && !defined(KMOD_MEMMAP))
#define USE_PAGECACHE
#endif
/* For how long should the cached page be valid */
#ifndef VT_CACHE_TIME_MS
#define VT_CACHE_TIME_MS 1
#endif
static size_t vtCacheTimeMS = VT_CACHE_TIME_MS;
#define VT_CACHE_TIME_NS vtCacheTimeMS * 1000000ll
static const uint64_t PMASK = (~0xfull << 8) & 0xfffffffffull;
static void FillRWInfo(const ProcessData* data, uint64_t dirBase, RWInfo* info, int* count, uint64_t local, uint64_t remote, size_t len);
static int FillRWInfoMul(const ProcessData* data, uint64_t dirBase, RWInfo* origData, RWInfo* info, size_t count);
static int CalculateDataCount(RWInfo* info, size_t count);
ssize_t VMemRead(const ProcessData* data, uint64_t dirBase, uint64_t local, uint64_t remote, size_t size)
{
if ((remote >> 12ull) == ((remote + size) >> 12ull))
return MemRead(data, local, VTranslate(data, dirBase, remote), size);
int dataCount = (int)((size - 1) / 0x1000) + 2;
RWInfo rdataStack[MAX_BATCHED_RW];
RWInfo* rdata = rdataStack;
if (dataCount > MAX_BATCHED_RW)
rdata = (RWInfo*)malloc(sizeof(RWInfo) * dataCount);
FillRWInfo(data, dirBase, rdata, &dataCount, local, remote, size);
ssize_t ret = MemReadMul(data, rdata, dataCount);
if (dataCount > MAX_BATCHED_RW)
free(rdata);
return ret;
}
ssize_t VMemWrite(const ProcessData* data, uint64_t dirBase, uint64_t local, uint64_t remote, size_t size)
{
if ((remote >> 12ull) == ((remote + size) >> 12ull))
return MemWrite(data, local, VTranslate(data, dirBase, remote), size);
int dataCount = (int)((size - 1) / 0x1000) + 2;
RWInfo wdataStack[MAX_BATCHED_RW];
RWInfo* wdata = wdataStack;
if (dataCount > MAX_BATCHED_RW)
wdata = (RWInfo*)malloc(sizeof(RWInfo) * dataCount);
FillRWInfo(data, dirBase, wdata, &dataCount, local, remote, size);
ssize_t ret = MemWriteMul(data, wdata, dataCount);
if (dataCount > MAX_BATCHED_RW)
free(wdata);
return ret;
}
uint64_t VMemReadU64(const ProcessData* data, uint64_t dirBase, uint64_t remote)
{
uint64_t dest;
MemRead(data, (uint64_t)&dest, VTranslate(data, dirBase, remote), sizeof(uint64_t));
return dest;
}
ssize_t VMemWriteU64(const ProcessData* data, uint64_t dirBase, uint64_t remote, uint64_t value)
{
return MemRead(data, (uint64_t)&value, VTranslate(data, dirBase, remote), sizeof(uint64_t));
}
uint64_t MemReadU64(const ProcessData* data, uint64_t remote)
{
uint64_t dest;
MemRead(data, (uint64_t)&dest, remote, sizeof(uint64_t));
return dest;
}
ssize_t MemWriteU64(const ProcessData* data, uint64_t remote, uint64_t value)
{
return MemRead(data, (uint64_t)&value, remote, sizeof(uint64_t));
}
ssize_t VMemReadMul(const ProcessData* data, uint64_t dirBase, RWInfo* info, size_t num)
{
int dataCount = CalculateDataCount(info, num);
RWInfo readInfoStack[MAX_BATCHED_RW];
RWInfo* readInfo = readInfoStack;
if (num > MAX_BATCHED_RW)
readInfo = (RWInfo*)malloc(sizeof(RWInfo) * num);
dataCount = FillRWInfoMul(data, dirBase, info, readInfo, num);
ssize_t ret = MemReadMul(data, readInfo, dataCount);
if (num > MAX_BATCHED_RW)
free(readInfo);
return ret;
}
ssize_t VMemWriteMul(const ProcessData* data, uint64_t dirBase, RWInfo* info, size_t num)
{
int dataCount = CalculateDataCount(info, num);
RWInfo writeInfoStack[MAX_BATCHED_RW];
RWInfo* writeInfo = writeInfoStack;
if (num > MAX_BATCHED_RW)
writeInfo = (RWInfo*)malloc(sizeof(RWInfo) * num);
dataCount = FillRWInfoMul(data, dirBase, info, writeInfo, num);
ssize_t ret = MemWriteMul(data, writeInfo, dataCount);
if (num > MAX_BATCHED_RW)
free(writeInfo);
return ret;
}
/*
This is used to cache the pages touched last bu reads of VTranslate, this increases the performance of external mode by at least 2x for multiple consequitive reads in common area. Cached page expires after a set interval which should be small enough not to cause very serious harm
*/
#if defined(USE_PAGECACHE) || !defined(NO_TLB)
static __thread struct timespec vtCurTime;
#endif
#ifdef USE_PAGECACHE
static __thread uint64_t vtCachePage[4] = { 0, 0, 0, 0 };
static __thread char vtCache[4][0x1000];
static __thread struct timespec vtCacheTime[4];
#endif
#ifndef NO_TLB
int vtTLBHits = 0;
int vtTLBMisses = 0;
typedef struct {
uint64_t page;
uint64_t dirBase;
uint64_t translation;
struct timespec resultTime;
} tlbentry_t;
// This makes the cache fit in 12 pages
#ifndef TLB_SIZE
#define TLB_SIZE 1024
#endif
static __thread tlbentry_t vtTlb[TLB_SIZE];
#endif
static size_t GetTlbIndex(uint64_t address) {
return (address >> 12l) % TLB_SIZE;
}
static void VtUpdateCurTime()
{
#if defined(USE_PAGECACHE) || !defined(NO_TLB)
clock_gettime(CLOCK_MONOTONIC_COARSE, &vtCurTime);
#endif
}
static uint64_t VtMemReadU64(const ProcessData* data, size_t idx, uint64_t address)
{
#ifdef USE_PAGECACHE
uint64_t page = address & ~0xfff;
uint64_t timeDiff = (vtCurTime.tv_sec - vtCacheTime[idx].tv_sec) * (uint64_t)1e9 + (vtCurTime.tv_nsec - vtCacheTime[idx].tv_nsec);
if (vtCachePage[idx] != page || timeDiff >= VT_CACHE_TIME_NS) {
MemRead(data, (uint64_t)vtCache[idx], page, 0x1000);
vtCachePage[idx] = page;
vtCacheTime[idx] = vtCurTime;
}
return *(uint64_t*)(void*)(vtCache[idx] + (address & 0xfff));
#else
(void)idx;
return MemReadU64(data, address);
#endif
}
static uint64_t VtCheckCachedResult(uint64_t inAddress, uint64_t dirBase)
{
VtUpdateCurTime();
#ifndef NO_TLB
tlbentry_t* tlb = &vtTlb[GetTlbIndex(inAddress)];
if ((tlb->dirBase == dirBase) && (tlb->page == (inAddress & ~0xfff))) {
uint64_t timeDiff = (vtCurTime.tv_sec - tlb->resultTime.tv_sec) * (uint64_t)1e9 + (vtCurTime.tv_nsec - tlb->resultTime.tv_nsec);
if (timeDiff < VT_CACHE_TIME_NS) {
vtTLBHits++;
return tlb->translation | (inAddress & 0xfff);
}
}
#endif
return 0;
}
static void VtUpdateCachedResult(uint64_t inAddress, uint64_t address, uint64_t dirBase)
{
#ifndef NO_TLB
tlbentry_t* tlb = &vtTlb[GetTlbIndex(inAddress)];
tlb->resultTime = vtCurTime;
tlb->translation = address & ~0xfff;
tlb->page = inAddress & ~0xfff;
tlb->dirBase = dirBase;
vtTLBMisses++;
#endif
}
/*
Translates a virtual address to a physical one. This (most likely) is windows specific and might need extra work to work on Linux target.
*/
static uint64_t VTranslateInternal(const ProcessData* data, uint64_t dirBase, uint64_t address)
{
uint64_t pageOffset = address & ~(~0ul << PAGE_OFFSET_SIZE);
uint64_t pte = ((address >> 12) & (0x1ffll));
uint64_t pt = ((address >> 21) & (0x1ffll));
uint64_t pd = ((address >> 30) & (0x1ffll));
uint64_t pdp = ((address >> 39) & (0x1ffll));
uint64_t pdpe = VtMemReadU64(data, 0, dirBase + 8 * pdp);
if (~pdpe & 1)
return 0;
uint64_t pde = VtMemReadU64(data, 1, (pdpe & PMASK) + 8 * pd);
if (~pde & 1)
return 0;
/* 1GB large page, use pde's 12-34 bits */
if (pde & 0x80)
return (pde & (~0ull << 42 >> 12)) + (address & ~(~0ull << 30));
uint64_t pteAddr = VtMemReadU64(data, 2, (pde & PMASK) + 8 * pt);
if (~pteAddr & 1)
return 0;
/* 2MB large page */
if (pteAddr & 0x80)
return (pteAddr & PMASK) + (address & ~(~0ull << 21));
address = VtMemReadU64(data, 3, (pteAddr & PMASK) + 8 * pte) & PMASK;
if (!address)
return 0;
return address + pageOffset;
}
uint64_t VTranslate(const ProcessData* data, uint64_t dirBase, uint64_t address)
{
dirBase &= ~0xf;
uint64_t cachedVal = VtCheckCachedResult(address, dirBase);
if (cachedVal)
return cachedVal;
cachedVal = VTranslateInternal(data, dirBase, address);
VtUpdateCachedResult(address, cachedVal, dirBase);
return cachedVal;
}
void SetMemCacheTime(size_t newTime)
{
if (newTime >= 0)
vtCacheTimeMS = newTime;
}
size_t GetDefaultMemCacheTime()
{
return VT_CACHE_TIME_MS;
}
/* Static functions */
static int CalculateDataCount(RWInfo* info, size_t count)
{
int ret = 0;
for (size_t i = 0; i < count; i++)
ret += ((info[i].remote + info[i].size - 1) >> 12ull) - (info[i].remote >> 12ull);
return ret;
}
static int FillRWInfoMul(const ProcessData* data, uint64_t dirBase, RWInfo* origData, RWInfo* info, size_t count)
{
int ret = 0;
for (size_t i = 0; i < count; i++) {
int lcount = 0;
FillRWInfo(data, dirBase, info + ret, &lcount, origData[i].local, origData[i].remote, origData[i].size);
ret += lcount;
}
return ret;
}
static void FillRWInfo(const ProcessData* data, uint64_t dirBase, RWInfo* info, int* count, uint64_t local, uint64_t remote, size_t len)
{
memset(info, 0, sizeof(RWInfo) * *count);
info[0].local = local;
info[0].remote = VTranslate(data, dirBase, remote);
info[0].size = 0x1000 - (remote & 0xfff);
#ifndef NO_ASSERTS
assert(!((remote + info[0].size) & 0xfff));
#endif
if (info[0].size > len)
info[0].size = len;
uint64_t curSize = info[0].size;
uint64_t tlen = 0;
int i = 1;
for (; curSize < len; curSize += 0x1000) {
info[i].local = local + curSize;
info[i].remote = VTranslate(data, dirBase, remote + curSize);
info[i].size = len - curSize;
if (info[i].size > 0x1000)
info[i].size = 0x1000;
if (info[i].remote) {
tlen += info[i].size;
i++;
}
}
*count = i;
}

@ -0,0 +1,226 @@
#ifndef MEM_H
#define MEM_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file mem.h
* @brief Defines memory operations
*
* Provides all necessary methods to read and write memory in a VM
*/
#include "definitions.h"
#define PAGE_OFFSET_SIZE 12
#define MAX_BATCHED_RW 1024
typedef struct RWInfo
{
uint64_t local;
uint64_t remote;
size_t size;
} RWInfo;
/**
* @brief Read a piece of data in physical VM address space
*
* @param data VM process data
* @param local local data address
* @param remote remote data address
* @param size size of data
*
* @return
* Data moved on success;
* -1 otherwise
*/
ssize_t MemRead(const ProcessData* data, uint64_t local, uint64_t remote, size_t size);
/**
* @brief Write a piece of data in physical VM address space
*
* @param data VM process data
* @param local local data address
* @param remote remote data address
* @param size size of data
*
* @return
* Data moved on success;
* -1 otherwise
*/
ssize_t MemWrite(const ProcessData* data, uint64_t local, uint64_t remote, size_t size);
/**
* @brief Read multiple pieces of data in physical VM address space
*
* @param data VM process data
* @param info list of information for RW operations
* @param num number of info atoms
*
* @return
* Data moved on success;
* -1 otherwise
*/
ssize_t MemReadMul(const ProcessData* data, RWInfo* info, size_t num);
/**
* @brief Write multiple pieces of data in physical VM address space
*
* @param data VM process data
* @param info list of information for RW operations
* @param num number of info atoms
*
* @return
* Data moved on success;
* -1 otherwise
*/
ssize_t MemWriteMul(const ProcessData* data, RWInfo* info, size_t num);
/**
* @brief Read a unsigned 64-bit integer in virtual VM address space
*
* @param data VM process data
* @param dirBase page table directory base of a process
* @param remote remote data address
*
* @return
* Read value, undefined on failure
*/
uint64_t VMemReadU64(const ProcessData* data, uint64_t dirBase, uint64_t remote);
/**
* @brief Write a unsigned 64-bit integer in virtual VM address space
*
* @param data VM process data
* @param dirBase page table directory base of a process
* @param remote remote data address
* @param value value to be written
*
* @return
* 8 on success;
* -1 on failure
*/
ssize_t VMemWriteU64(const ProcessData* data, uint64_t dirBase, uint64_t remote, uint64_t value);
/**
* @brief Read a unsigned 64-bit integer in physical VM address space
*
* @param data VM process data
* @param remote remote data address
*
* @return
* Read value, undefined on failure
*/
uint64_t MemReadU64(const ProcessData* data, uint64_t remote);
/**
* @brief Write a unsigned 64-bit integer in physical VM address space
*
* @param data VM process data
* @param remote remote data address
* @param value value to be written
*
* @return
* 8 on success;
* -1 on failure
*/
ssize_t MemWriteU64(const ProcessData* data, uint64_t remote, uint64_t value);
/**
* @brief Read data in virtual VM address space
*
* @param data VM process data
* @param dirBase page table directory base of a process
* @param local local data address
* @param remote remote data address
* @param size size of data
*
* @return
* Data moved on success;
* -1 otherwise
*/
ssize_t VMemRead(const ProcessData* data, uint64_t dirBase, uint64_t local, uint64_t remote, size_t size);
/**
* @brief Write data in virtual addresss space
*
* @param data VM process data
* @param dirBase page table directory base of a process
* @param local local data address
* @param remote remote data address
* @param size size of data
*
* @return
* Data moved on success;
* -1 otherwise
*/
ssize_t VMemWrite(const ProcessData* data, uint64_t dirBase, uint64_t local, uint64_t remote, size_t size);
/**
* @brief Read multiple pieces of data in virtual VM address space
*
* @param data VM process data
* @param dirBase page table directory base of a process
* @param info list of information for RW operations
* @param num number of info atoms
*
* @return
* Data moved on success;
* -1 otherwise
*/
ssize_t VMemReadMul(const ProcessData* data, uint64_t dirBase, RWInfo* info, size_t num);
/**
* @brief Write multiple pieces of data in virtual VM address space
*
* @param data VM process data
* @param dirBase page table directory base of a process
* @param info list of information for RW operations
* @param num number of info atoms
*
* @return
* Data moved on success;
* -1 otherwise
*/
ssize_t VMemWriteMul(const ProcessData* data, uint64_t dirBase, RWInfo* info, size_t num);
/**
* @brief Translate a virtual VM address into a physical one
*
* @param data VM process data
* @param dirBase page table directory base of a process
* @param address virtual address to translate
*
* @return
* Translated linear address;
* 0 otherwise
*/
uint64_t VTranslate(const ProcessData* data, uint64_t dirBase, uint64_t address);
/**
* @brief Set translation cache validity time in msecs
*
* @param newTime new validity length for a cache entry
*
* Defines for how long translation caches (TLB and page buffer) should be valid. Higher values lead to higher
* performance, but could potentially lead to incorrect translation if the page tables update in that period.
* Especially dangerous if write operations are to be performed.
*/
void SetMemCacheTime(size_t newTime);
/**
* @brief Get the default cache validity
*
* @return
* Default cache validity time
*/
size_t GetDefaultMemCacheTime();
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,69 @@
project('vmread', 'cpp', 'c', version : '1.3', default_options : ['c_std=c99', 'cpp_std=c++14'])
compile_args = ['-D_POSIX_C_SOURCE=200809L', '-D_DEFAULT_SOURCE', '-pedantic', '-DMVERBOSE=4', '-DMTR_ENABLED', '-DREAD_CHECK']
compile_args_external = ['-DLMODE=MODE_EXTERNAL', '-fsanitize=address']
compile_args_internal = ['-DLMODE=MODE_QEMU_INJECT', '-DMVERBOSE=4']
link_args_external = ['-lasan']
link_args_internal = []
link_args = ['-pthread','-lX11']
cpp_compile_args = []
c_compile_args = []
try_args = ['-Weverything', '-Wno-padded', '-Wno-sign-conversion', '-Wno-padded', '-Wno-documentation-unknown-command', '-Wno-missing-variable-declarations', '-Wno-c++98-compat', '-Wno-c++98-compat-pedantic', '-Wno-weak-vtables','-lX11','-pthread']
try_args_c = ['-Wno-missing-prototypes']
try_args_cpp = ['-Wno-padded', '-Wno-c++98-compat', '-Wno-padded', '-Wno-c++98-compat-pedantic', '-Wno-weak-vtables', '-Wno-documentation-unknown-command', '-Wno-old-style-cast']
cxx = meson.get_compiler('cpp')
cc = meson.get_compiler('c')
foreach arg : try_args
if cc.has_argument(arg)
c_compile_args += arg
endif
if cxx.has_argument(arg)
cpp_compile_args += arg
endif
endforeach
foreach arg : try_args_cpp
if cxx.has_argument(arg)
cpp_compile_args += arg
endif
endforeach
foreach arg : try_args_c
if cc.has_argument(arg)
c_compile_args += arg
endif
endforeach
dl = meson.get_compiler('c').find_library('dl', required : false)
thread = meson.get_compiler('c').find_library('pthread', required : false)
base_files = ['mem.c', 'wintools.c', 'pmparser.c']
hlapi_files = ['hlapi/windll.cpp', 'hlapi/winprocess.cpp', 'hlapi/winprocesslist.cpp']
apex_dma = executable(
'apex_dma',
files(base_files + ['../apex_dma/apex_dma.cpp', '../apex_dma/Game.cpp', '../apex_dma/Math.cpp', 'vmmem.c'] + hlapi_files),
c_args : c_compile_args + compile_args + compile_args_external,
cpp_args : cpp_compile_args + compile_args + compile_args_external,
link_args : compile_args + compile_args_external + link_args + link_args_external
)
apex_dma_kmod = executable(
'kmod_apex_dma',
files(base_files + ['../apex_dma/apex_dma.cpp', '../apex_dma/Game.cpp', '../apex_dma/Math.cpp', 'intmem.c'] + hlapi_files),
c_args : c_compile_args + compile_args + compile_args_external + ['-DKMOD_MEMMAP'],
cpp_args : cpp_compile_args + compile_args + compile_args_external + ['-DKMOD_MEMMAP'],
link_args : compile_args + compile_args_external + link_args + link_args_external
)
apex_dma_lib = shared_library(
'apex_dma',
files(base_files + ['../apex_dma/apex_dma.cpp', '../apex_dma/Game.cpp', '../apex_dma/Math.cpp', 'intmem.c'] + hlapi_files),
c_args : compile_args + compile_args_internal,
cpp_args : compile_args + compile_args_internal,
link_args : compile_args + compile_args_internal + link_args + link_args_internal,
dependencies: [dl]
)

@ -0,0 +1,23 @@
set logscale xy 2
set terminal pngcairo color solid
set object 1 rectangle from screen 0,0 to screen 1,1 fillcolor rgb"#888888" behind
set output "rwperf.png"
set title "Read performance (K - kernel mapped, E - external)"
set xlabel "Chunk size"
set ylabel "Read speed (MB/s)"
set xtics (0x8,0x10,0x100,0x1000,0x10000)
set format x "0x%x"
set key left top
set colorsequence classic
plot "read_kmod" using 1:2 title "K32 chunks" with lines,\
"read_kmod" using 1:4 title "K8 chunks" with lines dashtype '_.-',\
"read_kmod" using 1:6 title "K1 chunk" with lines dashtype '- ',\
"read_external" using 1:2 title "E32 chunks" with lines,\
"read_external" using 1:4 title "E8 chunks" with lines dashtype '_.-',\
"read_external" using 1:6 title "E1 chunk" with lines dashtype '- '

@ -0,0 +1,164 @@
#include "pmparser.h"
procmaps_struct* g_last_head = NULL;
procmaps_struct* g_current = NULL;
void _pmparser_split_line(
char*buf,char*addr1,char*addr2,
char*perm,char* offset,char* device,char*inode,
char* pathname){
int orig=0;
int i=0;
while(buf[i]!='-'){
addr1[i-orig]=buf[i];
i++;
}
addr1[i]='\0';
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
addr2[i-orig]=buf[i];
i++;
}
addr2[i-orig]='\0';
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
perm[i-orig]=buf[i];
i++;
}
perm[i-orig]='\0';
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
offset[i-orig]=buf[i];
i++;
}
offset[i-orig]='\0';
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
device[i-orig]=buf[i];
i++;
}
device[i-orig]='\0';
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i]!='\t' && buf[i]!=' '){
inode[i-orig]=buf[i];
i++;
}
inode[i-orig] = '\0';
pathname[0] = '\0';
while(buf[i]=='\t' || buf[i]==' ')
i++;
orig=i;
while(buf[i] != '\t' && buf[i] != ' ' && buf[i] != '\n'){
pathname[i-orig]=buf[i];
i++;
}
pathname[i-orig] = '\0';
}
/**
* pmparser_parse
* @param pid the process id whose memory map to be parser. the current process if pid<0
* @return list of procmaps_struct structers
*/
procmaps_struct* pmparser_parse(int pid){
char maps_path[500];
if(pid >= 0)
sprintf(maps_path,"/proc/%d/maps",pid);
else
sprintf(maps_path,"/proc/self/maps");
FILE* file = fopen(maps_path,"r");
if(!file)
return NULL;
int ind=0;char buf[3000];
char c;
procmaps_struct* list_maps=NULL;
procmaps_struct* tmp;
procmaps_struct* current_node=list_maps;
char addr1[20],addr2[20], perm[8], offset[20], dev[10],inode[30],pathname[600];
while(1){
if( (c=(char)fgetc(file))==EOF ) break;
fgets(buf+1,259,file);
buf[0]=c;
tmp= (procmaps_struct*)malloc(sizeof(procmaps_struct));
_pmparser_split_line(buf,addr1,addr2,perm,offset, dev,inode,pathname);
sscanf(addr1,"%lx",(long unsigned *)&tmp->addr_start);
sscanf(addr2,"%lx",(long unsigned *)&tmp->addr_end);
tmp->length = ((unsigned long)tmp->addr_end - (unsigned long)tmp->addr_start);
strcpy(tmp->perm,perm);
tmp->is_r = (perm[0]=='r');
tmp->is_w = (perm[1]=='w');
tmp->is_x = (perm[2]=='x');
tmp->is_p = (perm[3]=='p');
sscanf(offset,"%lx",(unsigned long*)&tmp->offset);
strcpy(tmp->dev,dev);
tmp->inode=atoi(inode);
strcpy(tmp->pathname,pathname);
tmp->next=NULL;
if(ind==0){
list_maps=tmp;
list_maps->next=NULL;
current_node=list_maps;
}
current_node->next=tmp;
current_node=tmp;
ind++;
}
g_last_head=list_maps;
return list_maps;
}
/**
* pmparser_next
* @description move between areas
*/
procmaps_struct* pmparser_next(){
if(g_last_head==NULL) return NULL;
if(g_current==NULL)
g_current=g_last_head;
else
g_current=g_current->next;
return g_current;
}
/**
* pmparser_free
* @description should be called at the end to free the resources
* @param maps_list the head of the list to be freed
*/
void pmparser_free(procmaps_struct* maps_list){
if(maps_list==NULL) return ;
procmaps_struct* act=maps_list;
procmaps_struct* nxt=act->next;
while(act!=NULL){
free(act);
act=nxt;
if(nxt!=NULL)
nxt=nxt->next;
}
}

@ -0,0 +1,84 @@
/*
@Author : ouadimjamal@gmail.com
@date : December 2015
Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation. No representations are made about the suitability of this
software for any purpose. It is provided "as is" without express or
implied warranty.
*/
#ifndef PMPARSER_H
#define PMPARSER_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
/**
* procmaps_struct
* @desc hold all the information about an area in the process's VM
*/
typedef struct procmaps_struct{
void* addr_start;
void* addr_end;
unsigned long length;
char perm[5];
short is_r;
short is_w;
short is_x;
short is_p;
long offset;
char dev[12];
int inode;
char pathname[600];
struct procmaps_struct* next;
} procmaps_struct;
extern procmaps_struct* g_last_head;
extern procmaps_struct* g_current;
void _pmparser_split_line(
char*buf,char*addr1,char*addr2,
char*perm,char* offset,char* device,char*inode,
char* pathname);
/**
* pmparser_parse
* @param pid the process id whose memory map to be parser. the current process if pid<0
* @return list of procmaps_struct structers
*/
procmaps_struct* pmparser_parse(int pid);
/**
* pmparser_next
* @description move between areas
*/
procmaps_struct* pmparser_next(void);
/**
* pmparser_free
* @description should be called at the end to free the resources
* @param maps_list the head of the list to be freed
*/
void pmparser_free(procmaps_struct* maps_list);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,11 @@
#ifndef PROCESSDATA_H
#define PROCESSDATA_H
typedef struct ProcessData
{
uint64_t mapsStart;
uint64_t mapsSize;
pid_t pid;
} ProcessData;
#endif

@ -0,0 +1,111 @@
#include "mem.h"
#include <stdlib.h>
#include <sys/uio.h>
#include <stdio.h>
#include <unistd.h>
/* Memory read implementation using linux process_vm_ functions */
/*
On windows, first 2^31 physical bytes are really allocated for various PCI device mappings and do not point to actual physical RAM (mmapped region in QEMU case).
It also differs on Windows XP. This should be solved by injecting code into the kernel to retrieve the actual physical memory map of the system
*/
extern uint64_t KFIXC;
extern uint64_t KFIXO;
uint64_t KFIXC = 0x80000000;
uint64_t KFIXO = 0x80000000;
#define KFIX2(x) ((x) < KFIXC ? (x) : ((x) - KFIXO))
ssize_t process_vm_readv(pid_t pid,
const struct iovec *local_iov,
unsigned long liovcnt,
const struct iovec *remote_iov,
unsigned long riovcnt,
unsigned long flags);
ssize_t process_vm_writev(pid_t pid,
const struct iovec *local_iov,
unsigned long liovcnt,
const struct iovec *remote_iov,
unsigned long riovcnt,
unsigned long flags);
ssize_t MemRead(const ProcessData* data, uint64_t localAddr, uint64_t remoteAddr, size_t len)
{
struct iovec local;
struct iovec remote;
local.iov_base = (void*)localAddr;
local.iov_len = len;
remote.iov_base = (void*)(data->mapsStart + KFIX2(remoteAddr));
remote.iov_len = len;
return process_vm_readv(data->pid, &local, 1, &remote, 1, 0);
}
ssize_t MemReadMul(const ProcessData* data, RWInfo* rdata, size_t num)
{
struct iovec local[__IOV_MAX];
struct iovec remote[__IOV_MAX];
size_t i = 0;
size_t startRead = 0;
ssize_t ret = 0;
for (i = 0; i < num; i++) {
local[i - startRead].iov_base = (void*)rdata[i].local;
local[i - startRead].iov_len = rdata[i].size;
remote[i - startRead].iov_base = (void*)(data->mapsStart + KFIX2(rdata[i].remote));
remote[i - startRead].iov_len = rdata[i].size;
if (i - startRead + 1 >= __IOV_MAX) {
ret = process_vm_readv(data->pid, local, __IOV_MAX, remote, __IOV_MAX, 0);
if (ret == -1)
return ret;
startRead = i + 1;
}
}
if (i != startRead)
ret = process_vm_readv(data->pid, local, i - startRead, remote, i - startRead, 0);
return ret;
}
ssize_t MemWrite(const ProcessData* data, uint64_t localAddr, uint64_t remoteAddr, size_t len)
{
struct iovec local;
struct iovec remote;
local.iov_base = (void*)localAddr;
local.iov_len = len;
remote.iov_base = (void*)(data->mapsStart + KFIX2(remoteAddr));
remote.iov_len = len;
return process_vm_writev(data->pid, &local, 1, &remote, 1, 0);
}
ssize_t MemWriteMul(const ProcessData* data, RWInfo* wdata, size_t num)
{
struct iovec local[__IOV_MAX];
struct iovec remote[__IOV_MAX];
size_t i;
size_t startWrite = 0;
ssize_t ret = 0;
for (i = 0; i < num; i++) {
local[i - startWrite].iov_base = (void*)wdata[i].local;
local[i - startWrite].iov_len = wdata[i].size;
remote[i - startWrite].iov_base = (void*)(data->mapsStart + KFIX2(wdata[i].remote));
remote[i - startWrite].iov_len = wdata[i].size;
if (i - startWrite >= (size_t)__IOV_MAX) {
ret = process_vm_writev(data->pid, local, __IOV_MAX, remote, __IOV_MAX, 0);
if (ret == -1)
return ret;
startWrite = i + 1;
}
}
if (i != startWrite)
ret = process_vm_writev(data->pid, local, i - startWrite, remote, i - startWrite, 0);
return ret;
}

@ -0,0 +1,265 @@
#ifndef WINSTRUCTS_H
#define WINSTRUCTS_H
/* Native windows structures with native naming to avoid confusion, 32 bit variants exist */
#include <stdint.h>
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */
#define IMAGE_DOS_SIGNATURE 0x5a4d /* MZ */
#define IMAGE_NT_SIGNATURE 0x4550 /* PE00 */
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
#define IMAGE_SIZEOF_SHORT_NAME 8
typedef struct _IMAGE_DOS_HEADER {
uint16_t e_magic;
uint16_t e_cblp;
uint16_t e_cp;
uint16_t e_crlc;
uint16_t e_cparhdr;
uint16_t e_minalloc;
uint16_t e_maxalloc;
uint16_t e_ss;
uint16_t e_sp;
uint16_t e_csum;
uint16_t e_ip;
uint16_t e_cs;
uint16_t e_lfarlc;
uint16_t e_ovno;
uint16_t e_res[4];
uint16_t e_oemid;
uint16_t e_oeminfo;
uint16_t e_res2[10];
int e_lfanew;
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
typedef struct _IMAGE_EXPORT_DIRECTORY {
uint32_t Characteristics;
uint32_t TimeDateStamp;
uint16_t MajorVersion;
uint16_t MinorVersion;
uint32_t Name;
uint32_t Base;
uint32_t NumberOfFunctions;
uint32_t NumberOfNames;
uint32_t AddressOfFunctions;
uint32_t AddressOfNames;
uint32_t AddressOfNameOrdinals;
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
typedef struct _IMAGE_FILE_HEADER {
uint16_t Machine;
uint16_t NumberOfSections;
uint32_t TimeDateStamp;
uint32_t PointerToSymbolTable;
uint32_t NumberOfSymbols;
uint16_t SizeOfOptionalHeader;
uint16_t Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef struct _IMAGE_DATA_DIRECTORY {
uint32_t VirtualAddress;
uint32_t Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
typedef struct _IMAGE_OPTIONAL_HEADER64 {
uint16_t Magic;
uint8_t MajorLinkerVersion;
uint8_t MinorLinkerVersion;
uint32_t SizeOfCode;
uint32_t SizeOfInitializedData;
uint32_t SizeOfUninitializedData;
uint32_t AddressOfEntryPoint;
uint32_t BaseOfCode;
uint64_t ImageBase;
uint32_t SectionAlignment;
uint32_t FileAlignment;
uint16_t MajorOperatingSystemVersion;
uint16_t MinorOperatingSystemVersion;
uint16_t MajorImageVersion;
uint16_t MinorImageVersion;
uint16_t MajorSubsystemVersion;
uint16_t MinorSubsystemVersion;
uint32_t Win32VersionValue;
uint32_t SizeOfImage;
uint32_t SizeOfHeaders;
uint32_t CheckSum;
uint16_t Subsystem;
uint16_t DllCharacteristics;
uint64_t SizeOfStackReserve;
uint64_t SizeOfStackCommit;
uint64_t SizeOfHeapReserve;
uint64_t SizeOfHeapCommit;
uint32_t LoaderFlags;
uint32_t NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
typedef struct _IMAGE_NT_HEADERS64 {
uint32_t Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS;
typedef struct _IMAGE_OPTIONAL_HEADER32 {
uint16_t Magic;
uint8_t MajorLinkerVersion;
uint8_t MinorLinkerVersion;
uint32_t SizeOfCode;
uint32_t SizeOfInitializedData;
uint32_t SizeOfUninitializedData;
uint32_t AddressOfEntryPoint;
uint32_t BaseOfCode;
uint32_t BaseOfData;
uint32_t ImageBase;
uint32_t SectionAlignment;
uint32_t FileAlignment;
uint16_t MajorOperatingSystemVersion;
uint16_t MinorOperatingSystemVersion;
uint16_t MajorImageVersion;
uint16_t MinorImageVersion;
uint16_t MajorSubsystemVersion;
uint16_t MinorSubsystemVersion;
uint32_t Win32VersionValue;
uint32_t SizeOfImage;
uint32_t SizeOfHeaders;
uint32_t CheckSum;
uint16_t Subsystem;
uint16_t DllCharacteristics;
uint32_t SizeOfStackReserve;
uint32_t SizeOfStackCommit;
uint32_t SizeOfHeapReserve;
uint32_t SizeOfHeapCommit;
uint32_t LoaderFlags;
uint32_t NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
typedef struct _IMAGE_NT_HEADERS32 {
uint32_t Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef struct _IMAGE_SECTION_HEADER {
uint8_t Name[IMAGE_SIZEOF_SHORT_NAME];
union {
uint32_t PhysicalAddress;
uint32_t VirtualSize;
} Misc;
uint32_t VirtualAddress;
uint32_t SizeOfRawData;
uint32_t PointerToRawData;
uint32_t PointerToRelocations;
uint32_t PointerToLinenumbers;
uint16_t NumberOfRelocations;
uint16_t NumberOfLinenumbers;
uint32_t Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
typedef struct _LIST_ENTRY
{
uint64_t f_link;
uint64_t b_link;
} LIST_ENTRY;
typedef struct _UNICODE_STRING
{
uint16_t length;
uint16_t maximum_length;
uint64_t buffer;
} UNICODE_STRING;
typedef struct _LDR_MODULE {
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
uint64_t BaseAddress;
uint64_t EntryPoint;
uint64_t SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
uint64_t Flags;
short LoadCount;
short TlsIndex;
LIST_ENTRY HashTableEntry;
uint64_t TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE;
typedef struct _PEB_LDR_DATA
{
uint64_t Length;
uint8_t Initialized;
uint64_t SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
uint64_t EntryInProgress;
} PEB_LDR_DATA;
typedef struct _PEB
{
uint8_t InheritedAddressSpace;
uint8_t ReadImageFileExecOptions;
uint8_t BeingFebugged;
uint8_t BitField;
uint8_t Padding0[4];
uint64_t Mutant;
uint64_t ImageBaseAddress;
uint64_t Ldr;
} PEB, PEB64;
typedef struct _LIST_ENTRY32
{
uint32_t f_link;
uint32_t b_link;
} LIST_ENTRY32;
typedef struct _UNICODE_STRING32
{
uint16_t length;
uint16_t maximum_length;
uint32_t buffer;
} UNICODE_STRING32;
typedef struct _LDR_MODULE32 {
LIST_ENTRY32 InLoadOrderModuleList;
LIST_ENTRY32 InMemoryOrderModuleList;
LIST_ENTRY32 InInitializationOrderModuleList;
uint32_t BaseAddress;
uint32_t EntryPoint;
uint32_t SizeOfImage;
UNICODE_STRING32 FullDllName;
UNICODE_STRING32 BaseDllName;
uint32_t Flags;
short LoadCount;
short TlsIndex;
LIST_ENTRY32 HashTableEntry;
uint32_t TimeDateStamp;
} LDR_MODULE32, *PLDR_MODULE32;
typedef struct _PEB_LDR_DATA32
{
uint32_t Length;
uint8_t Initialized;
uint32_t SsHandle;
LIST_ENTRY32 InLoadOrderModuleList;
LIST_ENTRY32 InMemoryOrderModuleList;
LIST_ENTRY32 InInitializationOrderModuleList;
uint32_t EntryInProgress;
} PEB_LDR_DATA32;
typedef struct _PEB32
{
uint8_t InheritedAddressSpace;
uint8_t ReadImageFileExecOptions;
uint8_t BeingFebugged;
uint8_t BitField;
uint32_t Mutant;
uint32_t ImageBaseAddress;
uint32_t Ldr;
} PEB32;
#endif

@ -0,0 +1,830 @@
#include "wintools.h"
#include "mem.h"
#include "pmparser.h"
#include <errno.h>
#include <string.h>
#ifdef KMOD_MEMMAP
#include "kmem.h"
#include <sys/mman.h>
#include <sys/ioctl.h>
#endif
#if (LMODE() != MODE_QEMU_INJECT())
#include <sys/types.h>
#include <dirent.h>
#endif
char* strdup(const char*);
static int CheckLow(const WinCtx* ctx, uint64_t* pml4, uint64_t* kernelEntry);
static void FindNTKernel(WinCtx* ctx, uint64_t kernelEntry);
static uint16_t GetNTVersion(const WinCtx* ctx);
static uint32_t GetNTBuild(const WinCtx* ctx);
static int SetupOffsets(WinCtx* ctx);
static WinModule GetBaseModule(const WinCtx* ctx, const WinProc* process);
static void FillAnyModuleList64(const WinCtx* ctx, const WinProc* process, WinModuleList* list, size_t* maxSize, uint64_t head, int inMemoryOrder);
static void FillModuleList64(const WinCtx* ctx, const WinProc* process, WinModuleList* list, size_t* maxSize, char* x86);
static void FillModuleList32(const WinCtx* ctx, const WinProc* process, WinModuleList* list, size_t* maxSize);
extern uint64_t KFIXC;
extern uint64_t KFIXO;
FILE* vmread_dfile = NULL;
#ifndef HEADER_SIZE
#define HEADER_SIZE 0x1000
#endif
#if (LMODE() != MODE_QEMU_INJECT())
static int RecursFind(const char* path, int level) {
if (level > 2)
return 0;
DIR* dir;
struct dirent* entry;
int ret = 0;
if (!(dir = opendir(path)))
return 0;
while (!ret && (entry = readdir(dir))) {
char npath[512];
if (entry->d_type == DT_DIR && ((level == 1 && entry->d_name[0] == 'f') ||
(entry->d_name[0] >= '0' && entry->d_name[0] <= '9'))) {
snprintf(npath, sizeof(npath), "%s/%s", path, entry->d_name);
ret = RecursFind(npath, level + 1);
} else if (level >= 2) {
snprintf(npath, sizeof(npath), "%s/%s", path, entry->d_name);
uint64_t dirv = 0;
const uint64_t kvm = *(uint64_t*)(void*)"/dev/kvm";
if (readlink(npath, (char*)&dirv, 8) == 8 && dirv == kvm)
sscanf(path, "/proc/%d/", &ret);
}
}
closedir(dir);
return ret;
}
#endif
static pid_t FindKVMProcess()
{
#if (LMODE() == MODE_QEMU_INJECT())
return getpid();
#else
pid_t ret = RecursFind("/proc", 0);
return ret > 0 ? ret : 0;
#endif
}
int InitializeContext(WinCtx* ctx, pid_t pid)
{
memset(ctx, 0, sizeof(WinCtx));
uint64_t pml4, kernelEntry;
if (pid == 0 && (pid = FindKVMProcess()) == 0)
return -1;
procmaps_struct* maps = pmparser_parse(pid);
if (!maps)
return 1;
procmaps_struct* tempMaps = NULL;
procmaps_struct* largestMaps = NULL;
while ((tempMaps = pmparser_next()) != NULL)
if (!largestMaps || tempMaps->length > largestMaps->length)
largestMaps = tempMaps;
if (!largestMaps)
return 2;
ctx->process.pid = pid;
ctx->process.mapsStart = (uint64_t)largestMaps->addr_start;
ctx->process.mapsSize = largestMaps->length;
pmparser_free(maps);
#ifdef KMOD_MEMMAP
MSG(2, "Mapping VM memory, this will take a second...\n");
int fd = open("/proc/vmread", O_RDWR);
if (fd != -1) {
int ret = ioctl(fd, VMREAD_IOCTL_MAPVMMEM, &ctx->process);
close(fd);
if (ret)
return 101;
} else
return 100;
#endif
MSG(2, "Mem:\t%lx\t| Size:\t%lx\n", ctx->process.mapsStart, ctx->process.mapsSize);
if (!CheckLow(ctx, &pml4, &kernelEntry))
return 3;
MSG(2, "PML4:\t%lx\t| KernelEntry:\t%lx\n", pml4, kernelEntry);
ctx->initialProcess.dirBase = pml4;
FindNTKernel(ctx, kernelEntry);
if (!ctx->ntKernel) {
/* Test in case we are running XP (QEMU AddressSpace is different) */
#if (LMODE() != MODE_DMA())
KFIXC = 0x40000000ll * 4;
KFIXO = 0x40000000;
FindNTKernel(ctx, kernelEntry);
#endif
if (!ctx->ntKernel)
return 4;
}
MSG(2, "Kernel Base:\t%lx (%lx)\n", ctx->ntKernel, VTranslate(&ctx->process, ctx->initialProcess.dirBase, ctx->ntKernel));
uint64_t initialSystemProcess = FindProcAddress(ctx->ntExports, "PsInitialSystemProcess");
if (!initialSystemProcess)
return 6;
MSG(2, "PsInitialSystemProcess:\t%lx (%lx)\n", initialSystemProcess, VTranslate(&ctx->process, ctx->initialProcess.dirBase, initialSystemProcess));
VMemRead(&ctx->process, ctx->initialProcess.dirBase, (uint64_t)&ctx->initialProcess.process, initialSystemProcess, sizeof(uint64_t));
if (!ctx->initialProcess.process)
return 7;
ctx->initialProcess.physProcess = VTranslate(&ctx->process, ctx->initialProcess.dirBase, ctx->initialProcess.process);
MSG(2, "System (PID 4):\t%lx (%lx)\n", ctx->initialProcess.process, ctx->initialProcess.physProcess);
ctx->ntVersion = GetNTVersion(ctx);
if (!ctx->ntVersion)
return 8;
MSG(2, "NT Version:\t%hu\n", ctx->ntVersion);
ctx->ntBuild = GetNTBuild(ctx);
if (!ctx->ntBuild)
return 8;
MSG(2, "NT Build:\t%u\n", ctx->ntBuild);
if (SetupOffsets(ctx))
return 9;
return 0;
}
int FreeContext(WinCtx* ctx)
{
FreeExportList(ctx->ntExports);
return 0;
}
IMAGE_NT_HEADERS* GetNTHeader(const WinCtx* ctx, const WinProc* process, uint64_t address, uint8_t* header, uint8_t* is64Bit)
{
if (VMemRead(&ctx->process, process->dirBase, (uint64_t)header, address, HEADER_SIZE) == -1)
return NULL;
//TODO: Allow the compiler to properly handle alignment
IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)(void*)header;
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
return NULL;
IMAGE_NT_HEADERS* ntHeader = (IMAGE_NT_HEADERS*)(void*)(header + dosHeader->e_lfanew);
if ((uint8_t*)ntHeader - header > HEADER_SIZE - 0x200 || ntHeader->Signature != IMAGE_NT_SIGNATURE)
return NULL;
if(ntHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC && ntHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
return NULL;
*is64Bit = ntHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC;
return ntHeader;
}
int ParseExportTable(const WinCtx* ctx, const WinProc* process, uint64_t moduleBase, IMAGE_DATA_DIRECTORY* exports, WinExportList* outList)
{
if (exports->Size < sizeof(IMAGE_EXPORT_DIRECTORY) || exports->Size > 0x7fffff || exports->VirtualAddress == moduleBase)
return 1;
char* buf = (char*)malloc(exports->Size + 1);
IMAGE_EXPORT_DIRECTORY* exportDir = (IMAGE_EXPORT_DIRECTORY*)(void*)buf;
if (VMemRead(&ctx->process, process->dirBase, (uint64_t)buf, moduleBase + exports->VirtualAddress, exports->Size) == -1) {
free(buf);
return 2;
}
buf[exports->Size] = 0;
if (!exportDir->NumberOfNames || !exportDir->AddressOfNames) {
free(buf);
return 3;
}
uint32_t exportOffset = exports->VirtualAddress;
uint32_t* names = (uint32_t*)(void*)(buf + exportDir->AddressOfNames - exportOffset);
if (exportDir->AddressOfNames - exportOffset + exportDir->NumberOfNames * sizeof(uint32_t) > exports->Size) {
free(buf);
return 4;
}
uint16_t* ordinals = (uint16_t*)(void*)(buf + exportDir->AddressOfNameOrdinals - exportOffset);
if (exportDir->AddressOfNameOrdinals - exportOffset + exportDir->NumberOfNames * sizeof(uint16_t) > exports->Size) {
free(buf);
return 5;
}
uint32_t* functions = (uint32_t*)(void*)(buf + exportDir->AddressOfFunctions - exportOffset);
if (exportDir->AddressOfFunctions - exportOffset + exportDir->NumberOfFunctions * sizeof(uint32_t) > exports->Size) {
free(buf);
return 6;
}
outList->size = exportDir->NumberOfNames;
outList->list = (WinExport*)malloc(sizeof(WinExport) * outList->size);
size_t sz = 0;
for (uint32_t i = 0; i < exportDir->NumberOfNames; i++) {
if (names[i] > exports->Size + exportOffset || names[i] < exportOffset || ordinals[i] > exportDir->NumberOfNames)
continue;
outList->list[sz].name = strdup(buf + names[i] - exportOffset);
outList->list[sz].address = moduleBase + functions[ordinals[i]];
sz++;
}
outList->size = sz;
free(buf);
return 0;
}
int GenerateExportList(const WinCtx* ctx, const WinProc* process, uint64_t moduleBase, WinExportList* outList)
{
uint8_t is64 = 0;
uint8_t headerBuf[HEADER_SIZE];
int ret = 0;
IMAGE_NT_HEADERS64* ntHeader64 = GetNTHeader(ctx, process, moduleBase, headerBuf, &is64);
if (!ntHeader64)
return -1;
IMAGE_NT_HEADERS32* ntHeader32 = (IMAGE_NT_HEADERS32*)ntHeader64;
IMAGE_DATA_DIRECTORY* exportTable = NULL;
if (is64)
exportTable = ntHeader64->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT;
else
exportTable = ntHeader32->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT;
ret = ParseExportTable(ctx, process, moduleBase, exportTable, outList);
return ret;
}
void FreeExportList(WinExportList list)
{
if (!list.list)
return;
for (uint32_t i = 0; i < list.size; i++)
free((char*)list.list[i].name);
free(list.list);
list.list = NULL;
}
/* TODO: do without the table parsing, we are just wasting a lot of string duplication etc. */
uint64_t GetProcAddress(const WinCtx* ctx, const WinProc* process, uint64_t module, const char* procName)
{
WinExportList exports;
if (GenerateExportList(ctx, process, module, &exports))
return 1;
uint64_t ret = FindProcAddress(exports, procName);
FreeExportList(exports);
return ret;
}
uint64_t FindProcAddress(const WinExportList exports, const char* procName)
{
for (uint32_t i = 0; i < exports.size; i++)
if (!strcmp(procName, exports.list[i].name))
return exports.list[i].address;
return 0;
}
WinProcList GenerateProcessList(const WinCtx* ctx)
{
WinProcList list;
uint64_t curProc = ctx->initialProcess.physProcess;
uint64_t virtProcess = ctx->initialProcess.process;
list.list = (WinProc*)malloc(sizeof(WinProc) * 25);
list.size = 0;
size_t maxSize = 25;
while (!list.size || (curProc != ctx->initialProcess.physProcess && virtProcess != ctx->initialProcess.process)) {
uint64_t stackCount = MemReadU64(&ctx->process, curProc + ctx->offsets.stackCount);
uint64_t dirBase = MemReadU64(&ctx->process, curProc + ctx->offsets.dirBase);
uint64_t pid = MemReadU64(&ctx->process, curProc + ctx->offsets.apl - 8);
/* The end of the process list usually has corrupted values, some sort of address, and we avoid the issue by checking the PID (which shouldn't be over 32 bit limit anyways) */
if (pid < 1u << 31 && stackCount) {
list.list[list.size] = (WinProc){
.process = virtProcess,
.physProcess = curProc,
.dirBase = dirBase,
.pid = pid,
};
WinModule baseMod = GetBaseModule(ctx, &list.list[list.size]);
if (baseMod.name)
list.list[list.size].name = baseMod.name;
else {
list.list[list.size].name = (char*)malloc(16);
MemRead(&ctx->process, (uint64_t)list.list[list.size].name, curProc + ctx->offsets.imageFileName, 15);
list.list[list.size].name[15] = '\0';
}
list.size++;
if (list.size > 1000 || pid == 0)
break;
}
if (list.size >= maxSize) {
maxSize = list.size * 2;
WinProc* newProc = (WinProc*)realloc(list.list, sizeof(WinProc) * maxSize);
if (!newProc)
break;
list.list = newProc;
}
virtProcess = MemReadU64(&ctx->process, curProc + ctx->offsets.apl) - ctx->offsets.apl;
if (!virtProcess)
break;
curProc = VTranslate(&ctx->process, dirBase, virtProcess);
if (!curProc)
break;
}
return list;
}
void FreeProcessList(WinProcList list)
{
size_t i;
if (list.list) {
for (i = 0; i < list.size; i++)
free(list.list[i].name);
free(list.list);
}
}
WinModuleList GenerateModuleList(const WinCtx* ctx, const WinProc* process)
{
WinModuleList list;
list.size = 0;
list.list = (WinModule*)malloc(sizeof(WinModule) * 25);
size_t maxSize = 25;
char x86 = 0;
FillModuleList64(ctx, process, &list, &maxSize, &x86);
if (x86)
FillModuleList32(ctx, process, &list, &maxSize);
return list;
}
WinModuleList GenerateKernelModuleList(const WinCtx* ctx)
{
WinModuleList list;
list.size = 0;
list.list = (WinModule*)malloc(sizeof(WinModule) * 25);
size_t maxSize = 25;
uint64_t psLoadedModuleList = FindProcAddress(ctx->ntExports, "PsLoadedModuleList");
FillAnyModuleList64(ctx, &ctx->initialProcess, &list, &maxSize, psLoadedModuleList, 0);
return list;
}
void FreeModuleList(WinModuleList list)
{
if (!list.list)
return;
for (size_t i = 0; i < list.size; i++)
free(list.list[i].name);
free(list.list);
list.list = NULL;
}
const WinModule* GetModuleInfo(const WinModuleList list, const char* moduleName)
{
for (size_t i = 0; i < list.size; i++)
if (!strcmp(list.list[i].name, moduleName))
return list.list + i;
return NULL;
}
PEB GetPeb(const WinCtx* ctx, const WinProc* process)
{
PEB peb;
uint64_t ppeb = MemReadU64(&ctx->process, process->physProcess + ctx->offsets.peb);
VMemRead(&ctx->process, process->dirBase, (uint64_t)&peb, ppeb, sizeof(PEB));
return peb;
}
PEB32 GetPeb32(const WinCtx* ctx, const WinProc* process)
{
PEB32 peb;
uint64_t ethread = MemReadU64(&ctx->process, process->physProcess + ctx->offsets.threadListHead) - ctx->offsets.threadListEntry;
uint64_t teb = VMemReadU64(&ctx->process, process->dirBase, ethread + ctx->offsets.teb) + 0x2000;
uint32_t ppeb;
VMemRead(&ctx->process, process->dirBase, (uint64_t)&ppeb, teb + ctx->offsets.peb32, sizeof(ppeb));
VMemRead(&ctx->process, process->dirBase, (uint64_t)&peb, ppeb, sizeof(PEB32));
return peb;
}
/*
The low stub (if exists), contains PML4 (kernel DirBase) and KernelEntry point.
Credits: PCILeech
*/
static int CheckLow(const WinCtx* ctx, uint64_t* pml4, uint64_t* kernelEntry)
{
int i, o;
char buf[0x10000];
for (i = 0; i < 10; i++) {
MemRead(&ctx->process, (uint64_t)buf, i * 0x10000, 0x10000);
for (o = 0; o < 0x10000; o += 0x1000) {
if(0x00000001000600E9 ^ (0xffffffffffff00ff & *(uint64_t*)(void*)(buf + o)))
continue;
if(0xfffff80000000000 ^ (0xfffff80000000000 & *(uint64_t*)(void*)(buf + o + 0x70)))
continue;
if(0xffffff0000000fff & *(uint64_t*)(void*)(buf + o + 0xa0))
continue;
*pml4 = *(uint64_t*)(void*)(buf + o + 0xa0);
*kernelEntry = *(uint64_t*)(void*)(buf + o + 0x70);
return 1;
}
}
return 0;
}
static void FindNTKernel(WinCtx* ctx, uint64_t kernelEntry)
{
uint64_t i, o, p, u, mask = 0xfffff;
char buf[0x10000];
ctx->ntKernel = 0;
while (mask >= 0xfff) {
for (i = (kernelEntry & ~0x1fffff) + 0x20000000; i > kernelEntry - 0x20000000; i -= 0x200000) {
for (o = 0; o < 0x20; o++) {
VMemRead(&ctx->process, ctx->initialProcess.dirBase, (uint64_t)buf, i + 0x10000 * o, 0x10000);
for (p = 0; p < 0x10000; p += 0x1000) {
if (((i + 0x1000 * o + p) & mask) == 0 && *(short*)(void*)(buf + p) == IMAGE_DOS_SIGNATURE) {
int kdbg = 0, poolCode = 0;
for (u = 0; u < 0x1000; u++) {
kdbg = kdbg || *(uint64_t*)(void*)(buf + p + u) == 0x4742444b54494e49;
poolCode = poolCode || *(uint64_t*)(void*)(buf + p + u) == 0x45444f434c4f4f50;
if (kdbg & poolCode) {
ctx->ntKernel = i + 0x10000 * o + p;
if (GenerateExportList(ctx, &ctx->initialProcess, ctx->ntKernel, &ctx->ntExports)) {
ctx->ntKernel = 0;
break;
}
return;
}
}
}
}
}
}
mask = mask >> 4;
}
}
static uint16_t GetNTVersion(const WinCtx* ctx)
{
uint64_t getVersion = FindProcAddress(ctx->ntExports, "RtlGetVersion");
if (!getVersion)
return 0;
char buf[0x100];
VMemRead(&ctx->process, ctx->initialProcess.dirBase, (uint64_t)buf, getVersion, 0x100);
char major = 0, minor = 0;
/* Find writes to rcx +4 and +8 -- those are our major and minor versions */
for (char* b = buf; b - buf < 0xf0; b++) {
if (!major && !minor)
if (*(uint32_t*)(void*)b == 0x441c748)
return ((uint16_t)b[4]) * 100 + (b[5] & 0xf);
if (!major && (*(uint32_t*)(void*)b & 0xfffff) == 0x441c7)
major = b[3];
if (!minor && (*(uint32_t*)(void*)b & 0xfffff) == 0x841c7)
minor = b[3];
}
if (minor >= 100)
minor = 0;
return ((uint16_t)major) * 100 + minor;
}
static uint32_t GetNTBuild(const WinCtx* ctx)
{
uint64_t getVersion = FindProcAddress(ctx->ntExports, "RtlGetVersion");
if (!getVersion)
return 0;
char buf[0x100];
VMemRead(&ctx->process, ctx->initialProcess.dirBase, (uint64_t)buf, getVersion, 0x100);
/* Find writes to rcx +12 -- that's where the version number is stored. These instructions are not on XP, but that is simply irrelevant. */
for (char* b = buf; b - buf < 0xf0; b++) {
uint32_t val = *(uint32_t*)(void*)b & 0xffffff;
if (val == 0x0c41c7 || val == 0x05c01b)
return *(uint32_t*)(void*)(b + 3);
}
return 0;
}
static int SetupOffsets(WinCtx* ctx)
{
switch (ctx->ntVersion) {
case 502: /* XP SP2 */
ctx->offsets = (WinOffsets){
.apl = 0xe0,
.session = 0x260,
.stackCount = 0xa0,
.imageFileName = 0x268,
.dirBase = 0x28,
.peb = 0x2c0,
.peb32 = 0x30,
.threadListHead = 0x290,
.threadListEntry = 0x3d0,
.teb = 0xb0
};
break;
case 601: /* W7 */
ctx->offsets = (WinOffsets){
.apl = 0x188,
.session = 0x2d8,
.stackCount = 0xdc,
.imageFileName = 0x2e0,
.dirBase = 0x28,
.peb = 0x338,
.peb32 = 0x30,
.threadListHead = 0x300,
.threadListEntry = 0x420, /* 0x428 on later SP1 */
.teb = 0xb8
};
/* SP1 */
if (ctx->ntBuild == 7601)
ctx->offsets.imageFileName = 0x2d8;
break;
case 602: /* W8 */
ctx->offsets = (WinOffsets){
.apl = 0x2e8,
.session = 0x430,
.stackCount = 0x234,
.imageFileName = 0x438,
.dirBase = 0x28,
.peb = 0x338, /*peb will be wrong on Windows 8 and 8.1*/
.peb32 = 0x30,
.threadListHead = 0x470,
.threadListEntry = 0x400,
.teb = 0xf0
};
break;
case 603: /* W8.1 */
ctx->offsets = (WinOffsets){
.apl = 0x2e8,
.session = 0x430,
.stackCount = 0x234,
.imageFileName = 0x438,
.dirBase = 0x28,
.peb = 0x338,
.peb32 = 0x30,
.threadListHead = 0x470,
.threadListEntry = 0x688, /* 0x650 on previous builds */
.teb = 0xf0
};
break;
case 1000: /* W10 */
ctx->offsets = (WinOffsets){
.apl = 0x2e8,
.session = 0x448,
.stackCount = 0x23c,
.imageFileName = 0x450,
.dirBase = 0x28,
.peb = 0x3f8,
.peb32 = 0x30,
.threadListHead = 0x488,
.threadListEntry = 0x6a8,
.teb = 0xf0
};
if (ctx->ntBuild >= 18362) { /* Version 1903 or higher */
ctx->offsets.apl = 0x2f0;
ctx->offsets.threadListEntry = 0x6b8;
}
break;
default:
return 1;
}
return 0;
}
static void FillModuleList64(const WinCtx* ctx, const WinProc* process, WinModuleList* list, size_t* maxSize, char* x86)
{
PEB peb = GetPeb(ctx, process);
PEB_LDR_DATA ldr;
memset(&ldr, 0, sizeof(ldr));
VMemRead(&ctx->process, process->dirBase, (uint64_t)&ldr, peb.Ldr, sizeof(ldr));
uint64_t head = ldr.InMemoryOrderModuleList.f_link;
size_t i = list->size ? list->size - 1 : list->size;
FillAnyModuleList64(ctx, process, list, maxSize, head, 1);
for (; i < list->size; i++) {
if (!strcmp(list->list[i].name, "wow64.dll")) {
*x86 = 1;
break;
}
}
}
static int FillModuleInfo64(const WinCtx* ctx, const WinProc* process, uint64_t* head, int inMemoryOrder, WinModule* modinfo)
{
const size_t NAME_LEN = 128;
wchar_t buf[128];
LDR_MODULE mod;
memset(&mod, 0, sizeof(mod));
VMemRead(&ctx->process, process->dirBase, (uint64_t)&mod, *head - sizeof(LIST_ENTRY) * inMemoryOrder, sizeof(mod));
VMemRead(&ctx->process, process->dirBase, (uint64_t)head, *head, sizeof(*head));
if (!mod.BaseDllName.length || !mod.SizeOfImage)
return 1;
/* Cap the module size */
if (mod.BaseDllName.length >= NAME_LEN)
mod.BaseDllName.length = NAME_LEN;
VMemRead(&ctx->process, process->dirBase, (uint64_t)buf, mod.BaseDllName.buffer, mod.BaseDllName.length * sizeof(wchar_t));
char* buf2 = (char*)malloc(mod.BaseDllName.length);
for (int i = 0; i < mod.BaseDllName.length; i++)
buf2[i] = ((char*)buf)[i*2];
buf2[mod.BaseDllName.length-1] = '\0';
if (*(short*)(void*)buf2 == 0x53) { /* 'S\0', a bit of magic, but it works */
free(buf2);
return 2;
}
modinfo->name = buf2;
modinfo->baseAddress = mod.BaseAddress;
modinfo->entryPoint = mod.EntryPoint;
modinfo->sizeOfModule = mod.SizeOfImage;
modinfo->loadCount = mod.LoadCount;
return 0;
}
static WinModule GetBaseModule(const WinCtx* ctx, const WinProc* process)
{
WinModule mod;
mod.name = NULL;
PEB peb = GetPeb(ctx, process);
PEB_LDR_DATA ldr;
memset(&ldr, 0, sizeof(ldr));
VMemRead(&ctx->process, process->dirBase, (uint64_t)&ldr, peb.Ldr, sizeof(ldr));
uint64_t head = ldr.InMemoryOrderModuleList.f_link;
uint64_t end = head;
uint64_t prev = head+1;
do {
prev = head;
if (!FillModuleInfo64(ctx, process, &head, 1, &mod)) {
if (mod.baseAddress == peb.ImageBaseAddress) {
break;
} else {
free(mod.name);
mod.name = NULL;
}
}
} while (head != end && head != prev);
return mod;
}
static void FillAnyModuleList64(const WinCtx* ctx, const WinProc* process, WinModuleList* list, size_t* maxSize, uint64_t head, int inMemoryOrder)
{
uint64_t end = head;
uint64_t prev = head+1;
if (inMemoryOrder)
inMemoryOrder = 1;
do {
if (list->size >= *maxSize) {
*maxSize *= 2;
WinModule* newList = (WinModule*)realloc(list->list, sizeof(WinModule) * *maxSize);
if (!newList)
break;
list->list = newList;
}
prev = head;
if (!FillModuleInfo64(ctx, process, &head, inMemoryOrder, list->list + list->size))
list->size++;
} while (head != end && head != prev);
}
static void FillModuleList32(const WinCtx* ctx, const WinProc* process, WinModuleList* list, size_t* maxSize)
{
PEB32 peb = GetPeb32(ctx, process);
PEB_LDR_DATA32 ldr;
memset(&ldr, 0, sizeof(ldr));
VMemRead(&ctx->process, process->dirBase, (uint64_t)&ldr, peb.Ldr, sizeof(ldr));
uint32_t head = ldr.InMemoryOrderModuleList.f_link;
uint32_t end = head;
uint32_t prev = head+1;
size_t nameBufSize = 128;
wchar_t* buf = (wchar_t*)malloc(sizeof(wchar_t) * nameBufSize);
do {
if (list->size >= *maxSize) {
*maxSize *= 2;
WinModule* newList = (WinModule*)realloc(list->list, sizeof(WinModule) * *maxSize);
if (!newList)
break;
list->list = newList;
}
prev = head;
LDR_MODULE32 mod;
memset(&mod, 0, sizeof(mod));
VMemRead(&ctx->process, process->dirBase, (uint64_t)&mod, head - sizeof(LIST_ENTRY32), sizeof(mod));
VMemRead(&ctx->process, process->dirBase, (uint64_t)&head, head, sizeof(head));
if (!mod.BaseDllName.length || !mod.SizeOfImage)
continue;
if (mod.BaseDllName.length >= nameBufSize) {
nameBufSize = mod.BaseDllName.length * 2;
buf = (wchar_t*)realloc(buf, sizeof(wchar_t) * nameBufSize);
}
VMemRead(&ctx->process, process->dirBase, (uint64_t)buf, mod.BaseDllName.buffer, mod.BaseDllName.length * sizeof(wchar_t));
char* buf2 = (char*)malloc(mod.BaseDllName.length);
for (int i = 0; i < mod.BaseDllName.length; i++)
buf2[i] = ((char*)buf)[i*2];
buf2[mod.BaseDllName.length-1] = '\0';
if (*(short*)(void*)buf2 == 0x53) {
free(buf2);
continue;
}
list->list[list->size].name = buf2;
list->list[list->size].baseAddress = mod.BaseAddress;
list->list[list->size].entryPoint = mod.EntryPoint;
list->list[list->size].sizeOfModule = mod.SizeOfImage;
list->list[list->size].loadCount = mod.LoadCount;
list->size++;
} while (head != end && head != prev);
free(buf);
}

@ -0,0 +1,280 @@
#ifndef WINTOOLS_H
#define WINTOOLS_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file wintools.h
* @brief Defines the main vmread functions
*
* Provides all utilities and structures for Windows operating systems.
*/
#include "definitions.h"
#include "winstructs.h"
typedef struct WinOffsets
{
int64_t apl;
int64_t session;
int64_t stackCount;
int64_t imageFileName;
int64_t dirBase;
int64_t peb;
int64_t peb32;
int64_t threadListHead;
int64_t threadListEntry;
int64_t teb;
} WinOffsets;
typedef struct WinProc
{
uint64_t process;
uint64_t physProcess;
uint64_t dirBase;
uint64_t pid;
char* name;
} WinProc;
typedef struct WinProcList
{
WinProc* list;
size_t size;
} WinProcList;
typedef struct WinExport
{
char* name;
uint64_t address;
} WinExport;
typedef struct WinExportList
{
WinExport* list;
size_t size;
} WinExportList;
typedef struct WinModule
{
uint64_t baseAddress;
uint64_t entryPoint;
uint64_t sizeOfModule;
char* name;
short loadCount;
} WinModule;
typedef struct WinModuleList
{
WinModule* list;
size_t size;
} WinModuleList;
typedef struct WinCtx
{
ProcessData process;
WinOffsets offsets;
uint64_t ntKernel;
uint16_t ntVersion;
uint32_t ntBuild;
WinExportList ntExports;
WinProc initialProcess;
} WinCtx;
/**
* @brief Initialize the vmread context
*
* @param ctx context to be initialized
* @param pid target process ID
*
* Initialize ctx by using pid. If pid is 0,
* the function tries to determine it automatically.
*
* @return
* 0 if initialization was successful;
* otherwise, the return value is an error value.
*/
int InitializeContext(WinCtx* ctx, pid_t pid);
/**
* @brief Free the vmread context
*
* @param ctx context to free
*
* It frees all the data inside the ctx making it free to be disposed
*
* @return
* Always 0
*/
int FreeContext(WinCtx* ctx);
/**
* @brief Get the NT header of a module
*
* @param ctx vmread context
* @param process target process
* @param address base address of the target module
* @param header buffer to read the header to
* @param is64Bit flag that returns if the module is 64-bit
*
* header has to be at least one page long, and @is64Bit can not be NULL.
*
* @return
* Pointer to the NT header, if it was found;
* otherwise @c NULL
*/
IMAGE_NT_HEADERS* GetNTHeader(const WinCtx* ctx, const WinProc* process, uint64_t address, uint8_t* header, uint8_t* is64Bit);
/**
* @brief Parse module export table, writing them to the export list
*
* @param ctx vmread context
* @param process target process
* @param moduleBase base address of the module
* @param exports address to the export table (parsed from the header)
* @param outList the list that gets the data written to
*
* @return
* 0 on success;
* Otherwise a positive error number indicating stage of the failure
*/
int ParseExportTable(const WinCtx* ctx, const WinProc* process, uint64_t moduleBase, IMAGE_DATA_DIRECTORY* exports, WinExportList* outList);
/**
* @brief Generate a module export list
*
* @param ctx vmread context
* @param process target process
* @param moduleBase base address
* @param outList the output list
*
* @return
* 0 on success;
* Otherwise either -1, or a positive number indicating stage of the failure
*/
int GenerateExportList(const WinCtx* ctx, const WinProc* process, uint64_t moduleBase, WinExportList* outList);
/**
* @brief Free the data inside the export list
*
* @param list list to be freed
*/
void FreeExportList(WinExportList list);
/**
* @brief Get the address of a module export
*
* @param ctx vmread context
* @param process target process
* @param module base address of the module
* @param procName target export name
*
* This function generates an export list and immediately frees it, so it is advised against using it extensively. See GetProcAddress.
*
* @return
* Virtual address of the export, 0, if not found
*/
uint64_t GetProcAddress(const WinCtx* ctx, const WinProc* process, uint64_t module, const char* procName);
/**
* @brief Find the proc address inside a given export list
*
* @param exports the list to be searched
* @param procName target export name
*
* @return
* Virtual address of the export, 0, if not found
*/
uint64_t FindProcAddress(const WinExportList exports, const char* procName);
/**
* @brief Generate the list of processes
*
* @param ctx vmread context
*
* @return
* A structure representing the process list
*/
WinProcList GenerateProcessList(const WinCtx* ctx);
/**
* @brief Free the data inside a process list
*
* @param list the list to have its data freed
*/
void FreeProcessList(WinProcList list);
/**
* @brief Generate the module list of a process
*
* @param ctx vmread context
* @param process target process
*
* @return
* A structure representing all modules loaded by the given process
*/
WinModuleList GenerateModuleList(const WinCtx* ctx, const WinProc* process);
/**
* @brief GenerateKernelModuleList
*
* @param ctx vmread context
*
* @return
* A structure representing all modules loaded by the kernel
*/
WinModuleList GenerateKernelModuleList(const WinCtx* ctx);
/**
* @brief Free a given module list
*
* @param list list to have its data freed in
*/
void FreeModuleList(WinModuleList list);
/**
* @brief Find the module by a given name
*
* @param list list to perform search in
* @param moduleName target module name
*
* @return
* A pointer to the found module information, @c NULL if not found
*/
const WinModule* GetModuleInfo(const WinModuleList list, const char* moduleName);
/**
* @brief Get the process environment block
*
* @param ctx vmread context
* @param process target process
*
* Note that there is no error checking in this function. Even though PEB should always exist,
* the returned data may be garbage
*
* @return
* The environment block
*/
PEB GetPeb(const WinCtx* ctx, const WinProc* process);
/**
* @brief Get the process environment block (32-bit version)
*
* @param ctx vmread context
* @param process target process
*
* Note that there is no error checking in this function. Even though PEB should always exist,
* the returned data may be garbage
*
* @return
* The environment block
*/
PEB32 GetPeb32(const WinCtx* ctx, const WinProc* process);
#ifdef __cplusplus
}
#endif
#endif
Loading…
Cancel
Save