Иконка ресурса

AutoLogin Interlude v5 5

Нет прав для скачивания


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

// Глобальные переменные
std::wstring WindowTitle = L"Lineage II";   // по умолчанию
HWND TargetWindow = nullptr;

// Типы функций
using SetTextFn = void(__thiscall*)(void*, const wchar_t*);

// Оригинальная функция и хук
SetTextFn OriginalSetText = nullptr;

// Хук для SetText
void __fastcall HookedSetText(void* thisptr, void*, const wchar_t* /*text*/) {
    TargetWindow = *(HWND*)((DWORD)thisptr + 4);
    SetWindowTextW(TargetWindow, WindowTitle.c_str());
}

// Установка хука
bool InstallHook() {
    HMODULE windowDll = GetModuleHandleW(L"Window.dll");
    if (!windowDll) return false;

    OriginalSetText = (SetTextFn)GetProcAddress(windowDll, "?SetText@WWindow@@UAEXPBG@Z");
    if (!OriginalSetText) return false;

    DWORD oldProtect;
    VirtualProtect(OriginalSetText, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
    *(BYTE*)OriginalSetText = 0xE9;
    *(DWORD*)((DWORD)OriginalSetText + 1) = (DWORD)HookedSetText - ((DWORD)OriginalSetText + 5);
    VirtualProtect(OriginalSetText, 5, oldProtect, &oldProtect);
    return true;
}

// Экспорт тестовых функций
extern "C" __declspec(dllexport) void __stdcall function1() {}
extern "C" __declspec(dllexport) void __stdcall L2ExportedFunction() {}

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

    class UL2ConsoleWnd {};
    UL2ConsoleWnd* UL2ConsoleWndPtr = nullptr;
    uintptr_t consoleOffset = 0x3663bc; // для IL клиента
}

class UNetworkHandler {};
typedef int(__fastcall* RequestAuthLoginFn)(UNetworkHandler*, int, const wchar_t*, const wchar_t*, int);
const uintptr_t unetworkOffset = 0x81F538;
UNetworkHandler** unetwork = nullptr;
RequestAuthLoginFn requestAuthLoginFn = nullptr;

// Конфиг для автологина
struct AutoLoginConfig {
    std::wstring login;
    std::wstring password;
    std::wstring title;   // новое поле
    int countenter = 0;
    int delay = 2000;
};

// --- хелперы ---
static std::wstring ToLower(std::wstring s) {
    for (auto& ch : s) ch = static_cast<wchar_t>(towlower(ch));
    return s;
}

static bool IsTrueValue(const std::wstring& v) {
    auto vl = ToLower(v);
    return (vl == L"1" || vl == L"true" || vl == L"yes" || vl == L"on");
}

// --- логин ---
static void RequestLogin(const std::wstring& login, const std::wstring& password) {
    if (!unetwork || !requestAuthLoginFn) return;
    if (login.empty() || password.empty()) return;
    requestAuthLoginFn(*unetwork, 0, login.c_str(), password.c_str(), 0);
}

// --- эмуляция Enter ---
static void SimulateEnter() {
    INPUT input[2] = {};
    input[0].type = INPUT_KEYBOARD;
    input[0].ki.wVk = VK_RETURN;

    input[1].type = INPUT_KEYBOARD;
    input[1].ki.wVk = VK_RETURN;
    input[1].ki.dwFlags = KEYEVENTF_KEYUP;

    SendInput(2, input, sizeof(INPUT));
}

// --- чтение настроек из ini файла ---
static bool ReadIniConfig(AutoLoginConfig& cfg) {
    wchar_t buffer[256] = { 0 };

    GetPrivateProfileStringW(L"AutoLogin", L"Login", L"", buffer, _countof(buffer), L".\\AutoLogin.ini");
    cfg.login = buffer;

    ZeroMemory(buffer, sizeof(buffer));
    GetPrivateProfileStringW(L"AutoLogin", L"Password", L"", buffer, _countof(buffer), L".\\AutoLogin.ini");
    cfg.password = buffer;

    ZeroMemory(buffer, sizeof(buffer));
    GetPrivateProfileStringW(L"AutoLogin", L"Title", L"", buffer, _countof(buffer), L".\\AutoLogin.ini");
    cfg.title = buffer;   // читаем title

    cfg.countenter = GetPrivateProfileIntW(L"AutoLogin", L"countenter", 0, L".\\AutoLogin.ini");
    cfg.delay = GetPrivateProfileIntW(L"AutoLogin", L"delay", 2000, L".\\AutoLogin.ini");

    // Возвращаем "готовность" только для логина, как и раньше
    return !cfg.login.empty() && !cfg.password.empty();
}

// --- парсинг аргументов командной строки ---
static bool ParseCommandLine(AutoLoginConfig& cfg, bool& anyArgsOut) {
    int argc = 0;
    LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
    if (!argv) { anyArgsOut = false; return false; }

    bool anyArgs = (argc > 1);

    for (int i = 1; i < argc; i++) {
        std::wstring arg = argv[i];
        if (arg.empty()) continue;

        if (arg[0] == L'/' || arg[0] == L'-') {
            arg.erase(0, 1);
        }

        size_t pos = arg.find(L'=');
        if (pos == std::wstring::npos) pos = arg.find(L':');

        std::wstring key = (pos == std::wstring::npos) ? arg : arg.substr(0, pos);
        std::wstring value = (pos == std::wstring::npos) ? L"1" : arg.substr(pos + 1);

        key = ToLower(key);

        if (key == L"account" || key == L"login" || key == L"user" || key == L"username") {
            cfg.login = value;
        }
        else if (key == L"password" || key == L"pass" || key == L"pwd") {
            cfg.password = value;
        }
        else if (key == L"countenter" || key == L"entercount") {
            cfg.countenter = _wtoi(value.c_str());
        }
        else if (key == L"delay" || key == L"enterdelay") {
            cfg.delay = _wtoi(value.c_str());
        }
        else if (key == L"title" || key == L"windowtitle") {
            cfg.title = value; // <--- забираем title из аргумента
        }
    }

    LocalFree(argv);
    anyArgsOut = anyArgs;
    // как и раньше, "успех" основан на наличии пары логин/пароль
    return !cfg.login.empty() && !cfg.password.empty();
}

static bool WaitForValidState(L2ConsoleState* statePtr) {
    DWORD startTime = GetTickCount();
    while (*statePtr == L2ConsoleState::Loading) {
        if (GetTickCount() - startTime > 30000) return false;
        Sleep(300);
    }

    if (*statePtr == L2ConsoleState::Login) return true;

    if (*statePtr == L2ConsoleState::Unknown) {
        startTime = GetTickCount();
        while (*statePtr == L2ConsoleState::Unknown) {
            if (GetTickCount() - startTime > 30000) return false;
            Sleep(300);
        }
        return (*statePtr == L2ConsoleState::Login);
    }

    return false;
}

// --- Функции для центрирования окна ---
struct FindWindowData {
    DWORD pid;
    HWND  hWnd;
};

static BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam)
{
    FindWindowData* data = reinterpret_cast<FindWindowData*>(lParam);
    DWORD wndPid;
    GetWindowThreadProcessId(hWnd, &wndPid);

    if (wndPid == data->pid) {
        wchar_t className[256];
        GetClassNameW(hWnd, className, ARRAYSIZE(className));
        if (wcscmp(className, L"L2UnrealWWindowsViewportWindow") == 0) {
            data->hWnd = hWnd;
            return FALSE; // нашли — прекращаем поиск
        }
    }
    return TRUE;
}

static HWND FindMyL2Window()
{
    FindWindowData data{};
    data.pid = GetCurrentProcessId();
    data.hWnd = nullptr;

    EnumWindows(EnumWindowsProc, reinterpret_cast<LPARAM>(&data));
    return data.hWnd;
}

static bool IsWindowFullscreen(HWND hWnd)
{
    RECT rcWnd, rcMon;
    if (!GetWindowRect(hWnd, &rcWnd)) return false;

    HMONITOR hMon = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
    MONITORINFO mi{ sizeof(mi) };
    if (!GetMonitorInfoW(hMon, &mi)) return false;

    rcMon = mi.rcMonitor;

    LONG style = GetWindowLongW(hWnd, GWL_STYLE);

    // fullscreen = окно занимает весь монитор И у него нет обычных рамок
    bool sizeMatch = (rcWnd.left == rcMon.left && rcWnd.top == rcMon.top &&
        rcWnd.right == rcMon.right && rcWnd.bottom == rcMon.bottom);

    bool hasBorders = (style & WS_OVERLAPPEDWINDOW) != 0;

    return (sizeMatch && !hasBorders);
}

static void CenterL2Window()
{
    HWND hWnd = nullptr;

    // ждём не более 5 секунд, потом выходим
    DWORD start = GetTickCount();
    while (!hWnd && (GetTickCount() - start < 5000)) {
        hWnd = FindMyL2Window();
        Sleep(500);
    }

    if (!hWnd) return; // окно не нашли — выходим

    if (IsWindowFullscreen(hWnd)) {
        return; // fullscreen — не трогаем
    }

    HMONITOR hMon = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
    MONITORINFO mi{ sizeof(mi) };
    GetMonitorInfoW(hMon, &mi);

    RECT rcWnd;
    GetWindowRect(hWnd, &rcWnd);
    int wndWidth = rcWnd.right - rcWnd.left;
    int wndHeight = rcWnd.bottom - rcWnd.top;

    int screenWidth = mi.rcWork.right - mi.rcWork.left;
    int screenHeight = mi.rcWork.bottom - mi.rcWork.top;

    int x = mi.rcWork.left + (screenWidth - wndWidth) / 2;
    int y = mi.rcWork.top + (screenHeight - wndHeight) / 2;

    SetWindowPos(hWnd, nullptr, x, y, 0, 0,
        SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
}

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

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

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

    // корректное вычисление адреса поля по смещению
    L2ConsoleState* statePtr = reinterpret_cast<L2ConsoleState*>(
        reinterpret_cast<uintptr_t>(UL2ConsoleWndPtr) + 0x38
        );

    bool authAttempted = false;

    while (true) {
        L2ConsoleState currentState = *statePtr;

        if (currentState == L2ConsoleState::Loading || currentState == L2ConsoleState::Unknown) {
            if (WaitForValidState(statePtr)) {
                currentState = *statePtr;
            }
            else {
                Sleep(5000);
                continue;
            }
        }

        if (currentState == L2ConsoleState::Login && !authAttempted) {
            AutoLoginConfig cfg;

            bool anyArgs = false;
            bool haveCmdCreds = ParseCommandLine(cfg, anyArgs);

            // --- ПРИМЕНЯЕМ TITLE СРАЗУ, НЕ ЗАВИСИМО ОТ КРЕДОВ ---
            if (!cfg.title.empty()) {
                WindowTitle = cfg.title; // из аргумента
            }
            else {
                // если в аргументах title нет — пробуем INI
                wchar_t tbuf[256] = {};
                GetPrivateProfileStringW(L"AutoLogin", L"Title", L"", tbuf, _countof(tbuf), L".\\AutoLogin.ini");
                if (tbuf[0] != L'\0') {
                    WindowTitle = tbuf;
                }
            }
            // -----------------------------------------------------

            if (anyArgs) {
                if (!haveCmdCreds) {
                    // есть арг-ты, но нет пары логин/пароль — логин не делаем
                    break;
                }
            }
            else {
                if (!ReadIniConfig(cfg)) {
                    // логин из ini недоступен — завершаемся
                    break;
                }
            }

            RequestLogin(cfg.login, cfg.password);
            authAttempted = true;

            if (cfg.countenter > 0) {
                for (int i = 0; i < cfg.countenter; i++) {
                    Sleep(cfg.delay);
                    SimulateEnter();
                }
            }

            Sleep(10000);
        }
        else if (currentState == L2ConsoleState::InGame) {
            break;
        }

        Sleep(3000);
    }
}

// --- Поток для центрирования окна ---
static DWORD WINAPI CenterThread(LPVOID)
{
    Sleep(1000); // ждём появления окна
    CenterL2Window();
    return 0;
}

// --- Поток для авторизации ---
static DWORD WINAPI AuthThread(LPVOID) {
    Sleep(1000);
    L2StatusLoad();
    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID) {
    if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
        DisableThreadLibraryCalls(hModule);

        // --- УСТАНАВЛИВАЕМ TITLE МАКСИМАЛЬНО РАНО (до хука и до первых SetText) ---
        {
            AutoLoginConfig tmp;
            bool any = false;
            // Используем ParseCommandLine только чтобы вытащить title (возврат игнорируем)
            (void)ParseCommandLine(tmp, any);

            if (!tmp.title.empty()) {
                WindowTitle = tmp.title; // приоритет — аргумент
            }
            else {
                wchar_t tbuf[256] = {};
                GetPrivateProfileStringW(L"AutoLogin", L"Title", L"", tbuf, _countof(tbuf), L".\\AutoLogin.ini");
                if (tbuf[0] != L'\0') {
                    WindowTitle = tbuf; // если в аргументах нет — берем из ini
                }
                // если и там пусто — останется Zaken
            }
        }
        // ----------------------------------------------------------------------------

        HMODULE engineModule = GetModuleHandleW(L"engine.dll");
        if (engineModule) {
            unetwork = reinterpret_cast<UNetworkHandler**>(reinterpret_cast<uintptr_t>(engineModule) + unetworkOffset);
            requestAuthLoginFn = (RequestAuthLoginFn)GetProcAddress(engineModule, "?RequestAuthLogin@UNetworkHandler@@UAEHPAG0H@Z");
        }

        InstallHook();

        // Запускаем оба потока
        CreateThread(nullptr, 0, CenterThread, nullptr, 0, nullptr);
        CreateThread(nullptr, 0, AuthThread, nullptr, 0, nullptr);
    }
    return TRUE;
}
Назад
Сверху