note. I've already released this little tut. on another forum and now i'm posting here as it is, don't blame me.
Hi, after years I decided to go back to Metin2.
So I decided to have fun calling python api functions directly in C++. I don't know if anyone has released a PoC yet, I haven't found anything here, so I'm releasing mine directly.
NOTE: You can get the same result by reversing and hooking functions directly, it's much easier.
1. First off we need to define a struct to hold our coordinates
Code:
struct vec3 {
double x, y, z;
};
2. Now let's create our function to retrieve the local player position from the Python function
Code:
vec3 GetMainCharacterPosition( PyObject* function ) {
PyObject* callObject = PyObject_CallObject( function, nullptr );
/* here we hold the position */
vec3 position;
/* check if the result is a tuple with at least 3 items */
if ( PyTuple_Check( callObject ) && PyTuple_GET_SIZE( callObject ) >= 3 ) {
/* then we extract them from the tuple */
PyObject* xObj = PyTuple_GetItem( callObject, 0 );
PyObject* yObj = PyTuple_GetItem( callObject, 1 );
PyObject* zObj = PyTuple_GetItem( callObject, 2 );
/* convert the objects to doubles and assign them to the struct */
position.x = PyFloat_AsDouble( xObj );
position.y = PyFloat_AsDouble( zObj );
position.z = PyFloat_AsDouble( yObj );
/* then we release the references to the objects */
Py_DECREF( xObj );
Py_DECREF( yObj );
Py_DECREF( zObj );
}
Py_DECREF( callObject );
return position;
}
3. After creating our function, let's call it
Code:
void init( ) {
sdk::utilities::setup_console( "test output" );
/* import the python module */
const auto& py_module = PyImport_ImportModule( "playerm2g2" );
/* get the function for retrieving the local player position */
const auto& py_func = PyObject_GetAttrString( py_module, "GetMainCharacterPosition" );
/* here we will store our temp coords */
double x, y, z;
bool ok = true;
while ( ok ) {
if ( GetAsyncKeyState( VK_HOME ) & 1 )
ok = false;
vec3 local_pos = GetMainCharacterPosition( py_func );
x = local_pos.x;
y = local_pos.y;
z = local_pos.z;
/* beautiful, innit? */
if ( x != 0 && y != 0 && z != 0 )
std::cout << "x: " << x << " | y: " << y << " | z: " << z << std::endl;
/* avoid excessive cpu usage */
std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) );
}
/* release the references to the objects after the loop */
Py_DECREF( py_func );
Py_DECREF( py_module );
/* cleanup */
FreeConsole( );
FreeLibraryAndExitThread( h_module, 0 );
}
BOOLEAN WINAPI DllMain( HINSTANCE hDllHandle, DWORD nReason, LPVOID Reserved )
{
switch ( nReason ) {
case DLL_PROCESS_ATTACH:
sdk::utilities::h_module = ( HMODULE )hDllHandle;
init( );
break;
}
return true;
}
4. Here you go.
If you don't know the Python Functions and Modules, here's a dump
NOTE: THIS DUMP IS FOR GF SERVER ( italy ), MAY BE DIFFERENT FOR PRIVATE SERVERS
Always good to see tutorials like this for new people to learn.
I few remarks for improvements:
At this point I itnk you will be limited to python functions by using this method. So I would rather inject a python script and call functions from there.
Also, I would avoid creating a new thread and calling game functions directly, i have experienced weird crashes because of the use of multiple threads. Metin2 was not designed to work with multiple threads so you might encounter race conditions in another functions that may crash the game.
Always good to see tutorials like this for new people to learn.
I few remarks for improvements:
At this point I itnk you will be limited to python functions by using this method. So I would rather inject a python script and call functions from there.
Also, I would avoid creating a new thread and calling game functions directly, i have experienced weird crashes because of the use of multiple threads. Metin2 was not designed to work with multiple threads so you might encounter race conditions in another functions that may crash the game.
Hi, thanks for ur suggestion
While testing I've already experienced crashes, but some crashes could be avoided by clearing references, obviously this is not the best way to interact with it, as you said it's better to inject a python script and do everything directly in python.
But ye, could be useful to someone that is trying to update old projects :P
For me, it took a few weeks to learn how to compile this code. So maybe you'll find some tips
1) Download Visual Studio Community 2022
Visual Studio 2022 takes up a lot of disk space for me, so I've chosen essential options.
Check:
Desktop development with C++
MSVC v143 - VS 2022 C++ x64/x86 build tools
Windows 11 SDK (10.0.22621.0)
You can create simple console application to check if visual studio works.
2) Download Python27
3) Create a new project -> Dynamic-Link-Library (DLL)
a) Change Debug to Release
b) Change x64 to x86
c) Debug -> HereIsNameOfYourProject DebugProperties
d) VC++ Directories -> Include Directories:
add path (check where you have Python27\include) -> C:\Python27\include
e) VC++ Directories -> Library Directories:
add path (check where you have Python27\libs) -> C:\Python27\libs
f) Linker -> Input -> Additional Dependencies
add python27.lib
4) Copy paste code:
Code:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <Python.h>
#include <thread>
#include <iostream>
struct vec3 {
double x, y, z;
};
vec3 GetMainCharacterPosition(PyObject* function) {
PyObject* callObject = PyObject_CallObject(function, nullptr);
/* here we hold the position */
vec3 position;
/* check if the result is a tuple with at least 3 items */
if (PyTuple_Check(callObject) && PyTuple_GET_SIZE(callObject) >= 3) {
/* then we extract them from the tuple */
PyObject* xObj = PyTuple_GetItem(callObject, 0);
PyObject* yObj = PyTuple_GetItem(callObject, 1);
PyObject* zObj = PyTuple_GetItem(callObject, 2);
/* convert the objects to doubles and assign them to the struct */
position.x = PyFloat_AsDouble(xObj);
position.y = PyFloat_AsDouble(zObj);
position.z = PyFloat_AsDouble(yObj);
/* then we release the references to the objects */
Py_DECREF(xObj);
Py_DECREF(yObj);
Py_DECREF(zObj);
}
Py_DECREF(callObject);
return position;
}
void init() {
//sdk::utilities::setup_console("test output");
AllocConsole();
freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
std::cout << "test output" << std::endl;
/* import the python module */
//const auto& py_module = PyImport_ImportModule("playerm2g2");
const auto& py_module = PyImport_ImportModule("rGuOnaAeJR"); // Check your module using program: Metin2 DragoDumper
if (py_module == nullptr) {
std::cout << "py_module = nullptr\n";
FreeConsole();
return;
}
/* get the function for retrieving the local player position */
const auto& py_func = PyObject_GetAttrString(py_module, "GetMainCharacterPosition");
/* here we will store our temp coords */
double x, y, z;
bool ok = true;
while (ok) {
if (GetAsyncKeyState(VK_HOME) & 1)
ok = false;
vec3 local_pos = GetMainCharacterPosition(py_func);
x = local_pos.x;
y = local_pos.y;
z = local_pos.z;
/* beautiful, innit? */
if (x != 0 && y != 0 && z != 0)
std::cout << "x: " << x << " | y: " << y << " | z: " << z << std::endl;
/* avoid excessive cpu usage */
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
/* release the references to the objects after the loop */
Py_DECREF(py_func);
Py_DECREF(py_module);
/* cleanup */
FreeConsole();
//FreeLibraryAndExitThread(h_module, 0);
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH: {
//sdk::utilities::h_module = (HMODULE)hDllHandle;
init();
FreeLibraryAndExitThread(hModule, 0);
}break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
5) Check name of your module
Here you'll find program to dump Python Functions and Modules:
6) Build program, it's not exe so if it worked you'll find this line in console:
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
7) Download program to inject dll, I use Extreme Injector (antivirus will block it)
8) Inject HereIsNameOfYourProject.dll to metin2client.exe
I wrote these steps but you'll find your own problems, errors, crashes which you have to fix. Maybe better if you start with small steps like:
I) Inject simple dll without Python.h to metin2, which only show message
II) Try to compile simple console program using in C++ Python.
I could made mistake in here, so use my stuff as tip.
For me, it took a few weeks to learn how to compile this code. So maybe you'll find some tips
1) Download Visual Studio Community 2022
Visual Studio 2022 takes up a lot of disk space for me, so I've chosen essential options.
Check:
Desktop development with C++
MSVC v143 - VS 2022 C++ x64/x86 build tools
Windows 11 SDK (10.0.22621.0)
You can create simple console application to check if visual studio works.
2) Download Python27
3) Create a new project -> Dynamic-Link-Library (DLL)
a) Change Debug to Release
b) Change x64 to x86
c) Debug -> HereIsNameOfYourProject DebugProperties
d) VC++ Directories -> Include Directories:
add path (check where you have Python27\include) -> C:\Python27\include
e) VC++ Directories -> Library Directories:
add path (check where you have Python27\libs) -> C:\Python27\libs
f) Linker -> Input -> Additional Dependencies
add python27.lib
4) Copy paste code:
Code:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <Python.h>
#include <thread>
#include <iostream>
struct vec3 {
double x, y, z;
};
vec3 GetMainCharacterPosition(PyObject* function) {
PyObject* callObject = PyObject_CallObject(function, nullptr);
/* here we hold the position */
vec3 position;
/* check if the result is a tuple with at least 3 items */
if (PyTuple_Check(callObject) && PyTuple_GET_SIZE(callObject) >= 3) {
/* then we extract them from the tuple */
PyObject* xObj = PyTuple_GetItem(callObject, 0);
PyObject* yObj = PyTuple_GetItem(callObject, 1);
PyObject* zObj = PyTuple_GetItem(callObject, 2);
/* convert the objects to doubles and assign them to the struct */
position.x = PyFloat_AsDouble(xObj);
position.y = PyFloat_AsDouble(zObj);
position.z = PyFloat_AsDouble(yObj);
/* then we release the references to the objects */
Py_DECREF(xObj);
Py_DECREF(yObj);
Py_DECREF(zObj);
}
Py_DECREF(callObject);
return position;
}
void init() {
//sdk::utilities::setup_console("test output");
AllocConsole();
freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
std::cout << "test output" << std::endl;
/* import the python module */
//const auto& py_module = PyImport_ImportModule("playerm2g2");
const auto& py_module = PyImport_ImportModule("rGuOnaAeJR"); // Check your module using program: Metin2 DragoDumper
if (py_module == nullptr) {
std::cout << "py_module = nullptr\n";
FreeConsole();
return;
}
/* get the function for retrieving the local player position */
const auto& py_func = PyObject_GetAttrString(py_module, "GetMainCharacterPosition");
/* here we will store our temp coords */
double x, y, z;
bool ok = true;
while (ok) {
if (GetAsyncKeyState(VK_HOME) & 1)
ok = false;
vec3 local_pos = GetMainCharacterPosition(py_func);
x = local_pos.x;
y = local_pos.y;
z = local_pos.z;
/* beautiful, innit? */
if (x != 0 && y != 0 && z != 0)
std::cout << "x: " << x << " | y: " << y << " | z: " << z << std::endl;
/* avoid excessive cpu usage */
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
/* release the references to the objects after the loop */
Py_DECREF(py_func);
Py_DECREF(py_module);
/* cleanup */
FreeConsole();
//FreeLibraryAndExitThread(h_module, 0);
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH: {
//sdk::utilities::h_module = (HMODULE)hDllHandle;
init();
FreeLibraryAndExitThread(hModule, 0);
}break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
5) Check name of your module
Here you'll find program to dump Python Functions and Modules:
6) Build program, it's not exe so if it worked you'll find this line in console:
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
7) Download program to inject dll, I use Extreme Injector (antivirus will block it)
8) Inject HereIsNameOfYourProject.dll to metin2client.exe
I wrote these steps but you'll find your own problems, errors, crashes which you have to fix. Maybe better if you start with small steps like:
I) Inject simple dll without Python.h to metin2, which only show message
II) Try to compile simple console program using in C++ Python.
I could made mistake in here, so use my stuff as tip.
Hi it works but i have a small problem.When i injected this dll game crashes like 5-10 minutes.C++ Runtime error how can i fix that ?
Always good to see tutorials like this for new people to learn.
I few remarks for improvements:
At this point I itnk you will be limited to python functions by using this method. So I would rather inject a python script and call functions from there.
Also, I would avoid creating a new thread and calling game functions directly, i have experienced weird crashes because of the use of multiple threads. Metin2 was not designed to work with multiple threads so you might encounter race conditions in another functions that may crash the game.
This is an explanation of why the game is crashing. I believe this is a dead end. I am not certain, but perhaps the correct solution is to unpack the root and make direct changes to the game there. Currently, I have given up because I did not find a solution, and I will not ask someone smarter than me for help.
Its cool I just wonder why do you call it in such a complicated way?
Cant you just write python code directly and execute it, e.g.:
dbg.LogBox(playerm2g2.GetMainCharacterPosition())
?
At this point I itnk you will be limited to python functions by using this method. So I would rather inject a python script and call functions from there.
The way you do it in your bot? With the exLib.dll and then the script.dll?
Can you further explain why is it better?
I've been trying to learn a little bit everyday so I don't need to depend on someone else's bot in the future.
For me, it took a few weeks to learn how to compile this code. So maybe you'll find some tips
1) Download Visual Studio Community 2022
Visual Studio 2022 takes up a lot of disk space for me, so I've chosen essential options.
Check:
Desktop development with C++
MSVC v143 - VS 2022 C++ x64/x86 build tools
Windows 11 SDK (10.0.22621.0)
You can create simple console application to check if visual studio works.
2) Download Python27
3) Create a new project -> Dynamic-Link-Library (DLL)
a) Change Debug to Release
b) Change x64 to x86
c) Debug -> HereIsNameOfYourProject DebugProperties
d) VC++ Directories -> Include Directories:
add path (check where you have Python27\include) -> C:\Python27\include
e) VC++ Directories -> Library Directories:
add path (check where you have Python27\libs) -> C:\Python27\libs
f) Linker -> Input -> Additional Dependencies
add python27.lib
4) Copy paste code:
Code:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <Python.h>
#include <thread>
#include <iostream>
struct vec3 {
double x, y, z;
};
vec3 GetMainCharacterPosition(PyObject* function) {
PyObject* callObject = PyObject_CallObject(function, nullptr);
/* here we hold the position */
vec3 position;
/* check if the result is a tuple with at least 3 items */
if (PyTuple_Check(callObject) && PyTuple_GET_SIZE(callObject) >= 3) {
/* then we extract them from the tuple */
PyObject* xObj = PyTuple_GetItem(callObject, 0);
PyObject* yObj = PyTuple_GetItem(callObject, 1);
PyObject* zObj = PyTuple_GetItem(callObject, 2);
/* convert the objects to doubles and assign them to the struct */
position.x = PyFloat_AsDouble(xObj);
position.y = PyFloat_AsDouble(zObj);
position.z = PyFloat_AsDouble(yObj);
/* then we release the references to the objects */
Py_DECREF(xObj);
Py_DECREF(yObj);
Py_DECREF(zObj);
}
Py_DECREF(callObject);
return position;
}
void init() {
//sdk::utilities::setup_console("test output");
AllocConsole();
freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
std::cout << "test output" << std::endl;
/* import the python module */
//const auto& py_module = PyImport_ImportModule("playerm2g2");
const auto& py_module = PyImport_ImportModule("rGuOnaAeJR"); // Check your module using program: Metin2 DragoDumper
if (py_module == nullptr) {
std::cout << "py_module = nullptr\n";
FreeConsole();
return;
}
/* get the function for retrieving the local player position */
const auto& py_func = PyObject_GetAttrString(py_module, "GetMainCharacterPosition");
/* here we will store our temp coords */
double x, y, z;
bool ok = true;
while (ok) {
if (GetAsyncKeyState(VK_HOME) & 1)
ok = false;
vec3 local_pos = GetMainCharacterPosition(py_func);
x = local_pos.x;
y = local_pos.y;
z = local_pos.z;
/* beautiful, innit? */
if (x != 0 && y != 0 && z != 0)
std::cout << "x: " << x << " | y: " << y << " | z: " << z << std::endl;
/* avoid excessive cpu usage */
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
/* release the references to the objects after the loop */
Py_DECREF(py_func);
Py_DECREF(py_module);
/* cleanup */
FreeConsole();
//FreeLibraryAndExitThread(h_module, 0);
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH: {
//sdk::utilities::h_module = (HMODULE)hDllHandle;
init();
FreeLibraryAndExitThread(hModule, 0);
}break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
5) Check name of your module
Here you'll find program to dump Python Functions and Modules:
6) Build program, it's not exe so if it worked you'll find this line in console:
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
7) Download program to inject dll, I use Extreme Injector (antivirus will block it)
8) Inject HereIsNameOfYourProject.dll to metin2client.exe
I wrote these steps but you'll find your own problems, errors, crashes which you have to fix. Maybe better if you start with small steps like:
I) Inject simple dll without Python.h to metin2, which only show message
II) Try to compile simple console program using in C++ Python.
I could made mistake in here, so use my stuff as tip.
Just a heads up: I encountered several unresolved external symbol __imp__ errors while attempting to compile the code. After investigating, I realized that I had mistakenly installed Python 2.7 64-bit instead of the 32-bit version.
Hi, i followed everything. But everytime i inject it, i get this output from cmd:
test output
py_module = nullptr
The "player" module might have different names on different servers.
Some have "player", some have "playerm2g2" and some might have just random names like "masndgasodpw". So you need to check whether the module name exists.
Function to return current player position 11/18/2018 - GW Bots - 0 Replies I'm currently working on the Boreal chest farm bot which from time to time get stuck behind the npc next to the gate.
I want to add a check of the current position of the players character.
So i could check the range between the player and a fix point to change the way he is using to run outside.
My problem is i cant find a function to return "Current Player Position"
Hope someone could help me :)
Finding current position of a player 01/07/2018 - DarkOrbit - 10 Replies Hello! Is it possible to find the map of any player who is online?
Edit: I mean something other than writing him in chat, adding him in contact list, joining his clan with another accout, etc.
Start Player Position 04/08/2010 - WoW Private Server - 1 Replies Hi
Weis einer wo man die Start Player Position verendern kann oder wie man es machen kann?
Mangos v0.3.7.5
danke
How to get X/Y position 03/01/2009 - SRO Hacks, Bots, Cheats & Exploits - 14 Replies Download: http://www.drewbenton.net/sro/0x33/demo/xy.../xypo sition.zip
Watch the first video link, it shows you everything you may want to know.
If you guys have any questions, feel free to ask. This is a public release so feel free
to share it.
=======================
Quote from 0x33
http://www.0x33.org/forum/showthread.php?t=9664