Попытка вызова функции RequestAutoShot из DLL.

  • Автор темы Автор темы gbcdev96
  • Дата начала Дата начала

gbcdev96

Путник
VIP
Сообщения
57
Розыгрыши
0
Репутация
0
Реакции
1
Баллы
31
Привет, ребята! Я пытаюсь разобраться, как работает исследование, и как я могу использовать функции из DLL в своей собственной DLL. В качестве примера я взял функцию RequestAutoShot.

Я начал с исследования функции RequestAutoSoulShot, И я нашел эти адреса в памяти:






С этим я думаю, что мне понадобится смещение uNetwork: 0x81F538 (я не уверен в этом утверждении).





Я нашел эту функцию, которая принимает networkHandler и l2ParamStack, и в итоге вызывает функцию FUN_10406880. Вот содержимое функции: FUN_10406880:


Мне показалось интересным, что он использует этот адрес: LAB_10880ab0.




но я ничего не нашел об этой функции, а потом пришел к выводу, что мне нужно смещение UNetworkHandler, и я не знаю, как я буду собирать L2ParamStack, я написал этот код на c++
Я не знаю, на правильном ли я пути, но мне кажется, что мне нужно понять, как я буду передавать идентификатор shoulshot в этот L2ParamStack, я до сих пор даже не знаю, какие методы и как Я использую его в своем коде, может ли кто-нибудь мне помочь?


C++:
#include "pch.h"
#include <windows.h>
#include <string>


extern "C" void __declspec(dllexport) __stdcall function1()
{
}


namespace {
    enum L2ConsoleState {
        Loading = 0,
        Unknown = 1,
        Login = 2,
        CharCreate = 3,
        CharSelect = 4,
        InGame = 5
    };


    class UL2ConsoleWnd {};
    UL2ConsoleWnd* UL2ConsoleWndPtr = nullptr;
    uintptr_t consoleOffset = 0x3663bc;
}




class UNetworkHandler {};


typedef void(__fastcall* RequestAutoSoulShotFn)(UNetworkHandler*, L2ParamStack*);


const uintptr_t unetworkOffset = 0x81F538;


UNetworkHandler** unetwork = nullptr;
RequestAutoSoulShotFn requestAutoSoulShotFn = nullptr;




static void RequestAutoSoulShot(int soulShotId) {
    if (!unetwork || !requestAutoSoulShotFn) {
        MessageBoxW(NULL, L"Erro: UNetworkHandler not initialized!", L"Debug", MB_OK);
        return;
    }


    // Instância de L2ParamStack




    // Chamar a função RequestAutoSoulShotFn com os parâmetros apropriados
    requestAutoSoulShotFn(*unetwork, &paramStack);


    MessageBoxW(NULL, L"RequestAutoSoulShot success!", L"Debug", MB_OK);
}


static void L2StatusLoad() {


    HMODULE hNwindowModule = nullptr;
    while (hNwindowModule == nullptr)
    {
        hNwindowModule = GetModuleHandleW(L"nwindow.dll");
        Sleep(1000);
    }


    uintptr_t pUL2ConsoleWnd = (reinterpret_cast<uintptr_t>(hNwindowModule)) + consoleOffset;


    while (UL2ConsoleWndPtr == nullptr)
    {
        UL2ConsoleWndPtr = *reinterpret_cast<UL2ConsoleWnd**>(pUL2ConsoleWnd);
        Sleep(300);
    }


    L2ConsoleState* statePtr = reinterpret_cast<L2ConsoleState*>(UL2ConsoleWndPtr + 0x38);


    while (true)
    {
        L2ConsoleState currentState = *statePtr;
        switch (currentState)
        {
        case L2ConsoleState::InGame:
            MessageBoxW(NULL, L"InGame", L"L2ConsoleState", MB_OK);
            RequestAutoSoulShot(3952);
            break;
        }
        Sleep(5000);
    }
}


static DWORD WINAPI TestThread(LPVOID lpParameter) {
    L2StatusLoad();
    return 0;
}




// Точка входа DLL
extern "C" __declspec(dllexport)
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved) {
    MessageBoxW(NULL, L"DLL Loading", L"L2ConsoleState", MB_OK);


    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        DisableThreadLibraryCalls(hModule);
        MessageBoxW(NULL, L"DLL Loaded", L"L2ConsoleState", MB_OK);
        HMODULE engineModule = GetModuleHandleW(L"engine.dll");
        if (engineModule) {
            unetwork = reinterpret_cast<UNetworkHandler**>(reinterpret_cast<uintptr_t>(engineModule) + unetworkOffset);
            requestAutoSoulShotFn = (RequestAutoSoulShotFn)GetProcAddress(engineModule,"?RequestAutoSoulShot@UNetworkHandler@@UAEXAAVL2ParamStack@@@Z");
        }


        CreateThread(nullptr, 0, TestThread, nullptr, 0, nullptr);
    }
    return TRUE;
}
 
C++:
template <class T>
struct TArray
{
    friend struct FString;

    public:
        inline TArray()
        {
            Data = nullptr;
            Count = Max = 0;
        };

        inline TArray(const size_t size)
        {
            Data = new T[size];
            Count = Max = 0;
        };

        inline void Add(T value)
        {
            Data[Count++] = value;
            Max++;
        }

        inline size_t Num() const
        {
            return Count;
        };

        inline T& operator[](size_t i)
        {
            return Data[i];
        };

        inline const T& operator[](size_t i) const
        {
            return Data[i];
        };

        inline bool IsValidIndex(size_t i) const
        {
            return i < Num();
        }

        inline T& GetByIndex(size_t i)
        {
            return Data[i];
        }

        inline const T& GetByIndex(size_t i) const
        {
            return Data[i];
        }

    private:
        T* Data;
        int32_t Count;
        int32_t Max;
};

struct FString : private TArray<wchar_t>
{
    FString() = default;

    FString(const wchar_t* other)
    {
        Max = Count = *other ? std::wcslen(other) + 1 : 0;

        if (Count)
        {
            Data = const_cast<wchar_t*>(other);
        }
    };

    inline bool IsValid() const
    {
        return Data != nullptr;
    }

    inline const wchar_t* c_str() const
    {
        return Data;
    }

    std::string ToString() const
    {
        auto length = std::wcslen(Data);

        std::string str(length, '\0');

        std::use_facet<std::ctype<wchar_t>>(std::locale()).narrow(Data, Data + length, '?', &str[0]);

        return str;
    }

    std::wstring ToWString() const
    {
        return std::wstring(c_str());
    }
};

struct L2ParamStack
    {
        public:
            TArray<uint64_t> m_Stack;
            int CurrentIndex;
            int StackSize;
            int StackTotalSize;

            L2ParamStack(): m_Stack(50), CurrentIndex(0), StackSize(0), StackTotalSize(0)
            {
            }

            void Push(uint64_t i)
            {
                m_Stack.Add(i);
                CurrentIndex++;
                StackSize++;
                StackTotalSize++;
            }

            void Restart()
            {
                CurrentIndex = 0;
            }
    };

And then you need push two params needed for packet (type 1 = on : 0 = off).
Guessed code:

C++:
void RequestAutoSoulShot(const uint32_t item_id, const uint32_t type)
    {
        L2ParamStack param_stack;
        param_stack.Push(item_id);
        param_stack.Push(type);
        param_stack.Restart();
        requestAutoSoulShotFn(*unetwork, &param_stack)
    }
 

Привет, спасибо!! У меня есть вопрос: у меня проблема с TARRAY, у вас есть заголовочный файл? Или вы сделали какую-то реализацию для него? Еще вопрос: как вы пришли к этим функциям в paramstack? Я не нашел его реализацию в DLL.
 
TArray's source also included in my answer. L2ParamStack reconstructed from decompile manually (i'm not sure it's a fully same with original, but works for me)
 
TArray's source also included in my answer. L2ParamStack reconstructed from decompile manually (i'm not sure it's a fully same with original, but works for me)

Вы могли бы мне помочь? Пакет доходит до сервера, но itemID и _type равны нулю. Я проверил, и подпись, кажется, правильная: RequestAutoSoulShot@UNetworkHandler@@UAEXAAVL2ParamStack@@@Z.

code:


C++:
#include "pch.h"
#include <windows.h>
#include <string>
#include <locale>

extern "C" void __declspec(dllexport) __stdcall function1()
{
}

namespace {
    enum L2ConsoleState {
        Loading = 0,
        Unknown = 1,
        Login = 2,
        CharCreate = 3,
        CharSelect = 4,
        InGame = 5
    };

    class UL2ConsoleWnd {};
    UL2ConsoleWnd* UL2ConsoleWndPtr = nullptr;
    uintptr_t consoleOffset = 0x3663bc;
}


template <class T>
struct TArray
{
    friend struct FString;

public:
    inline TArray()
    {
        Data = nullptr;
        Count = Max = 0;
    };

    inline TArray(const size_t size)
    {
        Data = new T[size];
        Count = Max = 0;
    };

    inline void Add(T value)
    {
        Data[Count++] = value;
        Max++;
    }

    inline size_t Num() const
    {
        return Count;
    };

    inline T& operator[](size_t i)
    {
        return Data[i];
    };

    inline const T& operator[](size_t i) const
    {
        return Data[i];
    };

    inline bool IsValidIndex(size_t i) const
    {
        return i < Num();
    }

    inline T& GetByIndex(size_t i)
    {
        return Data[i];
    }

    inline const T& GetByIndex(size_t i) const
    {
        return Data[i];
    }

private:
    T* Data;
    int32_t Count;
    int32_t Max;
};

struct FString : private TArray<wchar_t>
{
    FString() = default;

    FString(const wchar_t* other)
    {
        Max = Count = *other ? std::wcslen(other) + 1 : 0;

        if (Count)
        {
            Data = const_cast<wchar_t*>(other);
        }
    };

    inline bool IsValid() const
    {
        return Data != nullptr;
    }

    inline const wchar_t* c_str() const
    {
        return Data;
    }

    std::string ToString() const
    {
        auto length = std::wcslen(Data);

        std::string str(length, '\0');

        std::use_facet<std::ctype<wchar_t>>(std::locale()).narrow(Data, Data + length, '?', &str[0]);

        return str;
    }

    std::wstring ToWString() const
    {
        return std::wstring(c_str());
    }
};

struct L2ParamStack
{
public:
    TArray<uint64_t> m_Stack;
    int CurrentIndex;
    int StackSize;
    int StackTotalSize;

    L2ParamStack() : m_Stack(50), CurrentIndex(0), StackSize(0), StackTotalSize(0)
    {
    }

    void Push(uint64_t i)
    {
        m_Stack.Add(i);
        CurrentIndex++;
        StackSize++;
        StackTotalSize++;
    }

    void Restart()
    {
        CurrentIndex = 0;
    }
};

class UNetworkHandler {};

typedef void(__thiscall* RequestAutoSoulShotFn)(UNetworkHandler*, L2ParamStack*);

const uintptr_t unetworkOffset = 0x81F538;

UNetworkHandler** unetwork = nullptr;
RequestAutoSoulShotFn requestAutoSoulShotFn = nullptr;


static void RequestAutoSoulShot(const uint32_t item_id, const uint32_t type) {
    if (!unetwork || !requestAutoSoulShotFn) {
        MessageBoxW(NULL, L"Erro: UNetworkHandler not initialized!", L"Debug", MB_OK);
        return;
    }

    L2ParamStack param_stack;

    param_stack.Push(item_id);
    param_stack.Push(type);
    param_stack.Restart();

    wchar_t debugMsg[256];
    swprintf(debugMsg, 256, L"Item pushed: item_id=%llu, type=%llu",
        param_stack.m_Stack[0], param_stack.m_Stack[1]);

    MessageBoxW(NULL, debugMsg, L"Debug", MB_OK);

    requestAutoSoulShotFn(*unetwork, &param_stack);
}

static void L2StatusLoad() {

    HMODULE hNwindowModule = nullptr;
    while (hNwindowModule == nullptr)
    {
        hNwindowModule = GetModuleHandleW(L"nwindow.dll");
        Sleep(1000);
    }

    uintptr_t pUL2ConsoleWnd = (reinterpret_cast<uintptr_t>(hNwindowModule)) + consoleOffset;

    while (UL2ConsoleWndPtr == nullptr)
    {
        UL2ConsoleWndPtr = *reinterpret_cast<UL2ConsoleWnd**>(pUL2ConsoleWnd);
        Sleep(300);
    }

    L2ConsoleState* statePtr = reinterpret_cast<L2ConsoleState*>(UL2ConsoleWndPtr + 0x38);

    while (true)
    {
        L2ConsoleState currentState = *statePtr;
        switch (currentState)
        {
        case L2ConsoleState::InGame:
            MessageBoxW(NULL, L"InGame", L"L2ConsoleState", MB_OK);
            RequestAutoSoulShot(3952, 1);
            break;
        }
        Sleep(5000);
    }
}

static DWORD WINAPI TestThread(LPVOID lpParameter) {
    L2StatusLoad();
    return 0;
}


// Точка входа DLL
extern "C" __declspec(dllexport)
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved) {
    MessageBoxW(NULL, L"DLL Loading", L"L2ConsoleState", MB_OK);

    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        DisableThreadLibraryCalls(hModule);
        MessageBoxW(NULL, L"DLL Loaded", L"L2ConsoleState", MB_OK);
        HMODULE engineModule = GetModuleHandleW(L"engine.dll");
        if (engineModule) {
            unetwork = reinterpret_cast<UNetworkHandler**>(reinterpret_cast<uintptr_t>(engineModule) + unetworkOffset);
            requestAutoSoulShotFn = (RequestAutoSoulShotFn)GetProcAddress(engineModule,"?RequestAutoSoulShot@UNetworkHandler@@UAEXAAVL2ParamStack@@@Z");
        }

        CreateThread(nullptr, 0, TestThread, nullptr, 0, nullptr);
    }
    return TRUE;
}

 
I'm just tested in my own client extender and all works perfectly. But i'm using VT hooking for NetworkHandler.
So i'm not sure you are hooking RequestAutoSoulShot correctly.
 

    Amaranthe

    Баллов: 0
    to be лишний xD
I'm just tested in my own client extender and all works perfectly. But i'm using VT hooking for NetworkHandler.
So i'm not sure you are hooking RequestAutoSoulShot correctly.

I suspected that the problem might be the absence of the TOP() function, which is used in the code, but did you test it in the IL? I think my offset for NetworkHandler is correct, and maybe the issue is with the RequestAutoSoulShot function, because the packet reached my server, but it arrived with ss_id and type set to zero.
 
Ваша задача отправить правильную структуру, наличие или отсутствие метода ни на что не влияет. Я проверял только на High Five.
 
=) u are saying gibberish things , Push Is used to push something into some address/space and TOP -"translated" to get rid of something, in other words retrieve data from previous address/space into an variable/variables .

What could be the problem in HighFive vs Interlude is 64 32 bit space , stack could be TArray<uint32_t> m_Stack; that's first issue , but more like it that Tarray has incorrect alignment and structure data CurrentIndex has to be part of Tarray .

More of that int StackSize; logically its not StackSize its PushNum and it should be increased only once per call; like this PushNum=PushNum+ 1; and StackTotalSize its not StackTotalSize but TopPopNum and is increased once per call ( to the function) , if this won't be done then when original L2Top function is called in "?RequestAutoSoulShot@UNetworkHandler@@UAEXAAVL2ParamStack@@@Z" function it won't handle the data and return 0( because TopPopNum is allready bigger orEquals then PushNum ) ;
 
Последнее редактирование:
StackTotalSize = PushNum;
StackSize = TopPopNum ;
TopPopNum shouldn't be increased(Atleast)
 
I ended up getting confused; actually, I thought I needed to implement all the functions of ParamStack. I implemented a few, tested with int64, and it started sending the correct item_id value to the server. However, it seems something is happening where the index of _type is not being retrieved, and it always sends 0 to the server. I suspect it might be something in the stack implementation:









C++:
template <class T>
struct TArray
{
    friend struct FString;

public:
    inline TArray()
    {
        Data = nullptr;
        Count = Max = 0;
    };

    inline TArray(const size_t size)
    {
        Data = new T[size];
        Count = 0;
        Max = static_cast<int32_t>(size); // Defina o tamanho máximo corretamente
    };

    inline void Add(T value)
    {
        if (Count < Max) { // Certifique-se de que não exceda o limite
            Data[Count++] = value;
        }
    }

    inline size_t Num() const
    {
        return Count;
    };

    inline T& operator[](size_t i)
    {
        return Data[i];
    };

    inline const T& operator[](size_t i) const
    {
        return Data[i];
    };

    inline bool IsValidIndex(size_t i) const
    {
        return i < Num();
    }

    inline T& GetByIndex(size_t i)
    {
        return Data[i];
    }

    inline const T& GetByIndex(size_t i) const
    {
        return Data[i];
    }

    // Getter para o tamanho máximo
    inline int32_t GetMax() const
    {
        return Max;
    }

private:
    T* Data;
    int32_t Count;
    int32_t Max;
};

struct FString : private TArray<wchar_t>
{
    FString() = default;

    FString(const wchar_t* other)
    {
        Max = Count = *other ? std::wcslen(other) + 1 : 0;

        if (Count)
        {
            Data = const_cast<wchar_t*>(other);
        }
    };

    inline bool IsValid() const
    {
        return Data != nullptr;
    }

    inline const wchar_t* c_str() const
    {
        return Data;
    }

    std::string ToString() const
    {
        auto length = std::wcslen(Data);

        std::string str(length, '\0');

        std::use_facet<std::ctype<wchar_t>>(std::locale()).narrow(Data, Data + length, '?', &str[0]);

        return str;
    }

    std::wstring ToWString() const
    {
        return std::wstring(c_str());
    }
};

struct L2ParamStack
{
public:
    TArray<uint64_t> m_Stack;
    int PushNum;
    int TopPopNum;

    L2ParamStack() : m_Stack(50), PushNum(0), TopPopNum(0)
    {
    }

    int PushBack(uint64_t value)
    {
        m_Stack.Add(value);
        PushNum++;
        TopPopNum = PushNum;

        wchar_t debugMsg[256];
        swprintf(debugMsg, 256, L"PushBack: Value=%llu, PushNum=%d, TopPopNum=%d", value, PushNum, TopPopNum);
        MessageBoxW(NULL, debugMsg, L"Debug - PushBack", MB_OK);

        return PushNum;
    }

    void Restart()
    {
        TopPopNum = 0;
    }

};

class UNetworkHandler {};

typedef void(__thiscall* RequestAutoSoulShotFn)(UNetworkHandler*, L2ParamStack*);

const uintptr_t unetworkOffset = 0x81F538;

UNetworkHandler** unetwork = nullptr;
RequestAutoSoulShotFn requestAutoSoulShotFn = nullptr;


static void RequestAutoSoulShot(const uint64_t item_id, const uint64_t type) {
    if (!unetwork || !requestAutoSoulShotFn) {
        MessageBoxW(NULL, L"Erro: UNetworkHandler not initialized!", L"Debug", MB_OK);
        return;
    }

    L2ParamStack param_stack;

    param_stack.PushBack(type);
    param_stack.PushBack(item_id);
    param_stack.Restart();

    // Log do estado do L2ParamStack
    wchar_t debugMsg[256];
    swprintf(debugMsg, 256, L"L2ParamStack: Stack[0]=%llu, Stack[1]=%llu, PushNum=%d, TopPopNum=%d",
        param_stack.m_Stack[0], param_stack.m_Stack[1],
        param_stack.PushNum, param_stack.TopPopNum);
    MessageBoxW(NULL, debugMsg, L"Debug - L2ParamStack", MB_OK);

    requestAutoSoulShotFn(*unetwork, &param_stack);
}

static void L2StatusLoad() {

    HMODULE hNwindowModule = nullptr;
    while (hNwindowModule == nullptr)
    {
        hNwindowModule = GetModuleHandleW(L"nwindow.dll");
        Sleep(1000);
    }

    uintptr_t pUL2ConsoleWnd = (reinterpret_cast<uintptr_t>(hNwindowModule)) + consoleOffset;

    while (UL2ConsoleWndPtr == nullptr)
    {
        UL2ConsoleWndPtr = *reinterpret_cast<UL2ConsoleWnd**>(pUL2ConsoleWnd);
        Sleep(300);
    }

    L2ConsoleState* statePtr = reinterpret_cast<L2ConsoleState*>(UL2ConsoleWndPtr + 0x38);

    while (true)
    {
        L2ConsoleState currentState = *statePtr;
        switch (currentState)
        {
        case L2ConsoleState::InGame:
            MessageBoxW(NULL, L"InGame", L"L2ConsoleState", MB_OK);
            RequestAutoSoulShot(3952, 1);
            break;
        }
        Sleep(5000);
    }
}


It seems to me that what you mentioned is happening: the original Top function will correctly retrieve the last item added, but it is not retrieving the previous one, which is the _type.
 

Вложения

  • 1736453541320.webp
    19 КБ · Просмотры: 19
StackTotalSize = PushNum;
StackSize = TopPopNum ;
TopPopNum shouldn't be increased(Atleast)


thank you very much!! I finally got it hehe, the problem was really in uint64, my final code:


C++:
#include "pch.h"
#include <windows.h>
#include <string>
#include <locale>

extern "C" void __declspec(dllexport) __stdcall function1()
{
}

namespace {
    enum L2ConsoleState {
        Loading = 0,
        Unknown = 1,
        Login = 2,
        CharCreate = 3,
        CharSelect = 4,
        InGame = 5
    };

    class UL2ConsoleWnd {};
    UL2ConsoleWnd* UL2ConsoleWndPtr = nullptr;
    uintptr_t consoleOffset = 0x3663bc;
}

template <class T>
struct TArray
{
    friend struct FString;

public:
    inline TArray()
    {
        Data = nullptr;
        Count = Max = 0;
    };

    inline TArray(const size_t size)
    {
        Data = new T[size];
        Count = 0;
        Max = static_cast<int32_t>(size); // Defina o tamanho máximo corretamente
    };

    inline void Add(T value)
    {
        if (Count < Max) { // Certifique-se de que não exceda o limite
            Data[Count++] = value;
        }
    }

    inline size_t Num() const
    {
        return Count;
    };

    inline T& operator[](size_t i)
    {
        return Data[i];
    };

    inline const T& operator[](size_t i) const
    {
        return Data[i];
    };

    inline bool IsValidIndex(size_t i) const
    {
        return i < Num();
    }

    inline T& GetByIndex(size_t i)
    {
        return Data[i];
    }

    inline const T& GetByIndex(size_t i) const
    {
        return Data[i];
    }

    void Restart() {
        Count = 0;
    }

    // Getter para o tamanho máximo
    inline int32_t GetMax() const
    {
        return Max;
    }

private:
    T* Data;
    int32_t Count;
    int32_t Max;
};

struct FString : private TArray<wchar_t>
{
    FString() = default;

    FString(const wchar_t* other)
    {
        Max = Count = *other ? std::wcslen(other) + 1 : 0;

        if (Count)
        {
            Data = const_cast<wchar_t*>(other);
        }
    };

    inline bool IsValid() const
    {
        return Data != nullptr;
    }

    inline const wchar_t* c_str() const
    {
        return Data;
    }

    std::string ToString() const
    {
        auto length = std::wcslen(Data);

        std::string str(length, '\0');

        std::use_facet<std::ctype<wchar_t>>(std::locale()).narrow(Data, Data + length, '?', &str[0]);

        return str;
    }

    std::wstring ToWString() const
    {
        return std::wstring(c_str());
    }
};

struct L2ParamStack
{
public:
    TArray<uint32_t> m_Stack;
    int PushNum;
    int TopPopNum;

    L2ParamStack() : m_Stack(50), PushNum(0), TopPopNum(0)
    {
    }

    int Push(uint32_t value)
    {
        if (PushNum > m_Stack.GetMax()) {
            MessageBoxW(NULL, L"Erro: Stack cheio!", L"Debug - PushBack", MB_OK);
            return -1;
        }

        m_Stack.Add(value);
        PushNum++;
        TopPopNum = PushNum;

        return PushNum;

   /*     m_Stack.Add(value);
        PushNum++;
        TopPopNum = PushNum;

        wchar_t debugMsg[256];
        swprintf(debugMsg, 256, L"PushBack: Value=%llu, PushNum=%d, TopPopNum=%d", value, PushNum, TopPopNum);
        MessageBoxW(NULL, debugMsg, L"Debug - PushBack", MB_OK);

        return PushNum;*/
    }

    void Restart()
    {
        TopPopNum = 0;
        PushNum = 0;
        m_Stack.Restart();
    }
};

class UNetworkHandler {};

typedef void(__thiscall* RequestAutoSoulShotFn)(UNetworkHandler*, L2ParamStack*);

const uintptr_t unetworkOffset = 0x81F538;

UNetworkHandler** unetwork = nullptr;
RequestAutoSoulShotFn requestAutoSoulShotFn = nullptr;


static void RequestAutoSoulShot(const uint32_t item_id, const bool useSoulShot) {
    if (!unetwork || !requestAutoSoulShotFn) {
        MessageBoxW(NULL, L"Erro: UNetworkHandler not initialized!", L"Debug", MB_OK);
        return;
    }

    L2ParamStack param_stack;

    uint8_t type = useSoulShot ? 0x01 : 0x00;
    param_stack.Push(item_id);
    param_stack.Push(type);
    param_stack.Restart();
    // Log do estado do L2ParamStack
    wchar_t debugMsg[256];
    swprintf(debugMsg, 256, L"L2ParamStack: Stack[0]=%llu, Stack[1]=%llu, PushNum=%d, TopPopNum=%d",
        param_stack.m_Stack[0], param_stack.m_Stack[1],
        param_stack.PushNum, param_stack.TopPopNum);
    MessageBoxW(NULL, debugMsg, L"Debug - L2ParamStack", MB_OK);

    requestAutoSoulShotFn(*unetwork, &param_stack);
}

static void L2StatusLoad() {

    HMODULE hNwindowModule = nullptr;
    while (hNwindowModule == nullptr)
    {
        hNwindowModule = GetModuleHandleW(L"nwindow.dll");
        Sleep(1000);
    }

    uintptr_t pUL2ConsoleWnd = (reinterpret_cast<uintptr_t>(hNwindowModule)) + consoleOffset;

    while (UL2ConsoleWndPtr == nullptr)
    {
        UL2ConsoleWndPtr = *reinterpret_cast<UL2ConsoleWnd**>(pUL2ConsoleWnd);
        Sleep(300);
    }

    L2ConsoleState* statePtr = reinterpret_cast<L2ConsoleState*>(UL2ConsoleWndPtr + 0x38);

    while (true)
    {
        L2ConsoleState currentState = *statePtr;
        switch (currentState)
        {
        case L2ConsoleState::InGame:
            MessageBoxW(NULL, L"InGame", L"L2ConsoleState", MB_OK);
            RequestAutoSoulShot(3952, true);
            break;
        }
        Sleep(5000);
    }
}

static DWORD WINAPI TestThread(LPVOID lpParameter) {
    L2StatusLoad();
    return 0;
}


// Точка входа DLL
extern "C" __declspec(dllexport)
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved) {
    MessageBoxW(NULL, L"DLL Loading", L"L2ConsoleState", MB_OK);

    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        DisableThreadLibraryCalls(hModule);
        MessageBoxW(NULL, L"DLL Loaded", L"L2ConsoleState", MB_OK);
        HMODULE engineModule = GetModuleHandleW(L"engine.dll");
        if (engineModule) {
            unetwork = reinterpret_cast<UNetworkHandler**>(reinterpret_cast<uintptr_t>(engineModule) + unetworkOffset);
            requestAutoSoulShotFn = (RequestAutoSoulShotFn)GetProcAddress(engineModule,"?RequestAutoSoulShot@UNetworkHandler@@UAEXAAVL2ParamStack@@@Z");
        }

        CreateThread(nullptr, 0, TestThread, nullptr, 0, nullptr);
    }
    return TRUE;
}

Could you help me with one more question? If I want the function I created in the DLL, RequestAutoSoulShot, to be visible and usable in my .UC code, how could I achieve that?

I need to export this function:

C++:
extern "C" __declspec(dllexport) void RequestAutoSoulShot(const uint32_t item_id, const bool useSoulShot)
{
    // ... your function implementation ...
}

Add this native function to my .UC code (I’m not sure where I should add it).

C++:
native function RequestAutoSoulShot(int itemId, bool useSoulShot);

Do I need to do anything else, or is this enough?
 
idk how its working for u(maybe because of restart function) but this should be used as i mentioned before .

About second quesiton it was allready described on the forum here and here

Regarding TopPopNum, should I only increment it in the add method and never reset it? Would it be something like this:

C++:
struct L2ParamStack
{
public:
    TArray<uint32_t> m_Stack;
    int PushNum;
    int TopPopNum;

    L2ParamStack() : m_Stack(50), PushNum(0), TopPopNum(0)
    {
    }

    int Push(uint32_t value)
    {
        if (PushNum > m_Stack.GetMax()) {
            MessageBoxW(NULL, L"Erro: Stack cheio!", L"Debug - PushBack", MB_OK);
            return -1;
        }

        m_Stack.Add(value);
        PushNum++;
        TopPopNum++;

        return PushNum;

   /*     m_Stack.Add(value);
        PushNum++;
        TopPopNum = PushNum;

        wchar_t debugMsg[256];
        swprintf(debugMsg, 256, L"PushBack: Value=%llu, PushNum=%d, TopPopNum=%d", value, PushNum, TopPopNum);
        MessageBoxW(NULL, debugMsg, L"Debug - PushBack", MB_OK);

        return PushNum;*/
    }

    void Restart()
    {
        PushNum = 0;
        m_Stack.Restart();
    }
};

Could you help me with another question about these two threads? I can register the function correctly,
I tested it, and the registration worked.

C++:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"

#define RESULT_DECL void*const Result
typedef void (*Native)(struct FFrame& TheStack, RESULT_DECL);
typedef BYTE(__cdecl* GRegisterNative_fnType)(INT iNative, const Native& Func);
GRegisterNative_fnType volatile GRegisterNative_fn = NULL;

void RequestAutoSoulShot(struct FFrame& Stack, RESULT_DECL)
{
    MessageBox(nullptr, L"TEST", L"hook", MB_OK);
}

// Точка входа DLL
extern "C" __declspec(dllexport)
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved) {
    if (ul_reason_for_call != DLL_PROCESS_ATTACH) {
        return TRUE;     
    }

    auto hCore = GetModuleHandleA("Core.dll");
    if (!hCore) {
        MessageBoxW(NULL, L"FailedToGetHCore", L"hook", MB_OK);
        return true;
    }

    GRegisterNative_fn = (GRegisterNative_fnType)GetProcAddress(hCore, "?GRegisterNative@@YAEHABQ8UObject@@AEXAAUFFrame@@QAX@Z@Z");
    if (!GRegisterNative_fn) {
        MessageBox(nullptr, L"Nullable GRegisterNative_fn", L"hook", MB_OK);
        return true;
    }
    
    GRegisterNative_fn(4004, &RequestAutoSoulShot);

    return TRUE;
}

I just have two questions, actually. First, can I define this function at any point in my UC? For example, NWindow/UIScript.UC?

C++:
native(4004) final function RequestAutoSoulShot( int itemID, _type bool );

And I imagine that the declaration of my function that will be called in C++ should be: void RequestAutoSoulShot(struct FFrame&amp; Stack, RESULT_DECL), and somehow I need to extract the arguments itemID and _type from the stack? Can you tell me if that's correct?
 
when u push u push dont increment Top , its incremented when its being used .
at any point in my UC? For example, NWindow/UIScript.UC?
I'm not sure about that but u can/should define it in same Package/Script.uc that your Package.Dll name is , u can try to define it elsewhere in Nwindow.u or Interface.u but as far as i remember UScript Linker is looking in exact Package.dll for native function , i might be wrong.
arguments itemID and _type from the stack? Can you tell me if that's correct?
It depends on what u want that function to be doing, look for other similiar function implementation for that.
 
Got it, I understand about the stack now, thank you!!


I didn't understand this part: Package/Script.uc that your Package.Dll / UScript Linker is looking in exact Package.dll for native function. Do I need to have the exact name of my native function in my .UC file?

Basically, I wanted to call this function in this file: .UC AutoShotItemWnd.uc.

C++:
class AutoShotItemWnd extends UICommonAPI;

var WindowHandle zzMe;
var ItemWindowHandle zzinventory_item;
var ItemWindowHandle rhand;
var ItemInfo zziteminfoka;
var int _type;
var int _activateShotType;
var int _shotID;
var int zzkiaka2a;
var bool zzasnewk;
var ShortcutWnd zzshortcut;

function registerload()
{
    RegisterEvent(150);
    RegisterEvent(40);
    RegisterEvent(2610);
    RegisterEvent(693);
    RegisterEvent(44467);
    return;
}

function sendRequestToServer(optional int shotID, optional int _type)
{
    local string zParam;

    // End:0x21
    if( shotID > 10000 )
    {
        shotID = shotID - 10000;
    }

    RequestAutoSoulShot(shotID, True);

    //RequestBypassToServer((("RequestAutoShot: ShotID="$string(shotID))$" bEnable=")$string(_type));
    ParamAdd(zParam, "ShotID", string(shotID));
    ParamAdd(zParam, "bEnable", string(_type));
    
    if( _type == 1 )
    {
        ActivateAnimation(zParam);
    }

    return;
}

function OnLoad()
{    handleEquipRHandItem();
    registerload();
    inithandle();
    sendRequestToServer();
    return;
}

In this case, this function will only receive the SS ID and the type, and it will call the native function requestAutoSoulShot. From what I understand, I will have to extract the arguments from the stack to pass them to my C++ function, which will use UNetworkHandler::requestAutoSoulShot.
 
Данный сайт использует cookie. Вы должны принять их для продолжения использования. Узнать больше…