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

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

gbcdev96

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

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




1736393727069.webp

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


1736393940432.webp


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

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

1736394131355.webp
1736394158537.webp

но я ничего не нашел об этой функции, а потом пришел к выводу, что мне нужно смещение 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)
    }
 
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, у вас есть заголовочный файл? Или вы сделали какую-то реализацию для него? Еще вопрос: как вы пришли к этим функциям в 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. 1736440017517.webp

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;
}

1736440094133.webp
 
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.
 
Я подозревал, что проблема в отсутствии функции TOP(), которая используется в функции, но вы проверяли это в IL? Я думаю, что мой offset для NetworkHandler правильный, и, возможно, проблема в функции RequestAutoSoulShot, потому что пакет дошел до моего сервера, но он пришел с нулевыми значениями ss_id и type.
Ваша задача отправить правильную структуру, наличие или отсутствие метода ни на что не влияет. Я проверял только на High Five.
 
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.
=) 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)
 
=) 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 ) ;
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: 1736453490401.webp

1736453497625.webp

1736453515878.webp


1736453551408.webp


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
    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.
 
quando você empurra, você empurra, não aumenta o topo, ele é incrementado quando está sendo usado.

Não tenho certeza sobre isso, mas você pode/deve defini-lo no mesmo Package/Script.uc que seu nome Package.Dll é, você pode tentar defini-lo em outro lugar em Nwindow.u ou Interface.u, mas pelo que me lembro O UScript Linker está procurando no Package.dll exato a função nativa, posso estar errado.

Depende do que você deseja que essa função faça, procure outra implementação de função semelhante para isso.
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.
 
Назад
Сверху Снизу