@__fastcall Нашел
Проверил, работает нормально. Спасибо за совет.
@__fastcall Нашел
@__fastcall Я видел как люди пишут AsmJit библиотеки. Но такой вариант не вариант. Мне не хочется подключать стороннюю библиотеку. Я даже не стал использовать ни MinHook ни PolyHook ни им подобные.
Хотя нет, я все же посмотрел как работает MinHook и написал нечто похожее. Чисто для себя. Без авто-дизасемблера. С ручным заданием офсетов и длин.
std::unordered_map<std::string, std::unique_ptr<Hook::Signature>> Camera::createSignatures() {
std::unordered_map<std::string, std::unique_ptr<Signature>>signatures;
Hook::Instruction instruction{};
instruction.instructionsCount = 1;
instruction.totalByteLength = 5;
instruction.byteLengthPerInstruction.push_back(5);
signatures.emplace("FreezeFOV", std::make_unique<Signature>("FreezeFOV",
"F3 0F 11 4B 14 41 B6 01",
instruction, 0));
instruction.instructionsCount = 2;
instruction.totalByteLength = 6;
instruction.byteLengthPerInstruction.clear();
instruction.byteLengthPerInstruction.push_back(2);
instruction.byteLengthPerInstruction.push_back(4);
signatures.emplace("CheckPlayerInCar", std::make_unique<Signature>("CheckPlayerInCar",
"40 53 48 83 EC 30 80 79 60 00",
instruction, 0));
return signatures;
}
Моя идея состоит в том, чтобы написать класс генерирующий байты регистровых инструкций. Например в signatures записывается нужный регистр и имя поля класса (переменной) с ним связанным. Далее этот класс в месте трамплина, сразу за ним, запишет эти байты регистровых инструкций. Занес в signatures три регистра и три поля, значит будет три инструкции, сразу за трамплином. А после третьей инструкции, будет jmp на трамплин, из которого будет jmp на hook функцию, из которой будет потом jmp на трамплин до jmp на hook, выполниться пролог, и наконец jmp обратно в оригинальный код плюс оффсет на пролог.
@__fastcall Насколько мне известно, Visual Studio не поддерживает вставки для x64.
Вообще, у меня есть одна идея, но я хотел узнать и другие варианты.
Привет, подскажите, каким способом вы сохраняете значение регистра используя С++?
Речь идет о 64 битной архитектуре.
К регистрам (RCX, RDX, R8, R9), которые связаны со входными параметрами функции, получить доступ просто. Но как быть с другими регистрам, R10, R11?
Не использовать же приостановку потока со взятием его контекста.
К примеру есть игровая функция из пяти строк. В этой функции нужно получить значение R13 и сделать свои дела.
Искать ли место выше где R13 принимает нужное значение? Но там могут быть такие глубокие дебри.
@Antonshka
Можно без readProcessMemory так
template <typename T> requires EventConnectConcept<T>
VOID Event::connect(EventStatus(T::* method)(EventMessage*), T* listener, BOOL mustSkipIfDuplicate) {
...
CONST auto* CONST methodAddress = *reinterpret_cast<VOID**>(&method);
...
}
class MyWindow : public Window {
MyWindow () :
openSomething(new SButton(TRUE, 0, 0, L"Open Something", 10, 10, 100, 30, this))
{
openSomething->onLButtonUp->connect(&MyWindow ::someMethod, this);
...
}
...
private:
EventStatus someMethod(EventMessage* message);
private:
SButton* CONST openSomething{};
}
Привет всем.
Подскажите, нормально ли то, что я читаю указатель на метод класса с помощью ReadProcessMemory?
Более подходящего способа идентифицировать метод класса я не нашел и не придумал.
Я заметил при разных тестах, при использовании Cheat Engine и его memory view, что адрес в параметре method - (VOID connect(VOID(T::* method)(VOID), T* object)), в разных проектах имеет разную вложенность. Например, в одном проекте этот method указывает на jmp инструкцию, перейдя по которой, я попадаю на метод класса, в другом проекте, method указывает на адрес, который содержит этот же jmp . Я честно говоря не понял, почему там так, а здесь иначе.
Вот псевдокод. Это самодельная система сигналов//слотов
#include <iostream>
#include <utility>
#include <type_traits>
#include <Windows.h>
#include <vector>
class Button;
class Widget;
class Slot {
public:
virtual VOID call() = 0;
virtual BOOL isContain(DWORD_PTR methodAddress, DWORD_PTR objectAddress) = 0;
};
template <typename T>
class SlotMethod : public Slot {
public:
SlotMethod(VOID(T::* method)(VOID), T* object, DWORD_PTR methodAddress, DWORD_PTR objectAddress) :
method(method),
object(object),
methodAddress(methodAddress),
objectAddress(objectAddress)
{}
public:
virtual VOID call() override {
((*object).*method)();
}
virtual BOOL isContain(DWORD_PTR methodAddress, DWORD_PTR objectAddress) {
return (this->methodAddress == methodAddress && this->objectAddress == objectAddress);
}
private:
VOID(T::* method)(VOID);
T* object;
DWORD_PTR methodAddress{ 0 };
DWORD_PTR objectAddress{ 0 };
};
class Event {
public:
template <class T>
requires (std::is_base_of_v<Widget, std::remove_pointer_t<T>>)
VOID connect(VOID(T::* method)(VOID), T* object) {
if (method && object) {
DWORD_PTR methodAddress{ 0 };
ReadProcessMemory(GetCurrentProcess(), &method, &methodAddress, sizeof(methodAddress), NULL);
DWORD_PTR objectAddress{ reinterpret_cast<DWORD_PTR>(object) };
SlotMethod<T>* slotMethod{ new SlotMethod<T>{ method, object, methodAddress, objectAddress } };
listeners.emplace_back(slotMethod);
}
}
template <class T>
requires (std::is_base_of_v<Widget, std::remove_pointer_t<T>>)
VOID disconnect(VOID(T::* method)(VOID), T* object) {
if (method && object) {
DWORD_PTR methodAddress{ 0 };
ReadProcessMemory(GetCurrentProcess(), &method, &methodAddress, sizeof(methodAddress), NULL);
DWORD_PTR objectAddress{ reinterpret_cast<DWORD_PTR>(object) };
listeners.erase(std::remove_if(listeners.begin(), listeners.end(), [&](auto& listener) {
Slot* slot{ listener };
BOOL isContain{ slot->isContain(methodAddress, objectAddress) };
if (isContain) {
delete slot;
}
return isContain;
}), listeners.end());
}
}
VOID callListeners() {
for (auto& listener : listeners) {
listener->call();
}
}
private:
std::vector<Slot*> listeners;
};
class Widget {};
class Button : public Widget {
public:
VOID onLButtonDown(VOID) {
std::cout << "Button class - onLButtonDown method executed" << std::endl;
onLButtonDownEvent.callListeners();
}
public:
Event onLButtonDownEvent{};
};
class ButtonCustom : public Button {
public:
VOID print(VOID) {
std::cout << "I am a ButtonCustom method print" << std::endl;
}
};
int main() {
Button* button = new Button{};
ButtonCustom* custom = new ButtonCustom{};
button->onLButtonDownEvent.connect(&ButtonCustom::print, custom);
button->onLButtonDown();
button->onLButtonDownEvent.disconnect(&ButtonCustom::print, custom);
return 0;
}
Предполагаю что ошибка в отсутствии pushfq и popfq.
Инструкция cmp меняет флаги. По правильному нужно всегда сохранять/восстанавливать регистр EFLAGS.
newmem:
pushfq
cmp [hot_key],01
jne short @F
mov [r14+000003BC],(float)1000
mov [hot_key],00
@@:
popfq
mulss xmm14,[r14+000003BC]
jmp return