めいくりぷとのブログ

技術的なことやゲームのことやら・・・

めいぷるぷるるるる

youtu.be

タブのcloseボタンのuiなんとかセネバ...

struct AutoLogin
{
...
};

struct CMappedFile
{
    unsigned long request;
    unsigned long arg[10];

    AutoLogin login;
    ...
};

共有メモリの構造体がこんな感じなので、
[client] -> [server] は、request, argに値入れて、server側でrequestに対応する処理実行させてる。
[server] -> [client] は、client側でmemcpy使って、serverチェックするスレッドにぶっ込んで、各構造体読み取ってる。

今更だけど、テンプレートクラス便利すぎ。

めいぷる 更新

youtu.be

・サーバー(メイプル)の生存チェック
・その他もろもろ

後はgui側の切り替えと、メイプルクラッシュ時に再起動でござる~

めいぷる

youtu.be

@@

接続切り替える度に元の接続は切断(メモリ開放)してるんだけど、1回接続したらそのまま保持した方がええんかの?

クライアント (nullp system) 
        |-サーバー (メイプル1)
        |-サーバー (メイプル2)
        |-サーバー (メイプル3)
        ...

って感じなんだけど、最終的にサーバー同士でデータの共有もしたいから、多分それに変更しないとアレですな。
変更加えるのなら今の内って気がしなくもないけど、やる気が()

AVA 更新

gyazo.com

何やら変なクラスが追加されましたの...
まあ avaGame/avaRules/Engine/AVANET 辺りしか触れないからどうでもいいんですけど...

それと今まではsplash画像はファイルチェックの対象外でフォルダごと消すだけで良かったけど、アプデ入ってから毎回全ファイルチェックされる糞仕様に変わったのでってことで。
ファイルチェックはPmangDownloaderに対してReadFile辺りフックしときゃなんとかなる。(知らないけど
無駄に3つくらい起動するから、proxy dllとかで全部にフックかければok

スプラッシュウィンドウ非表示

void Detour_CreateWindowExW()
{
	static decltype(&CreateWindowExW) _CreateWindowExW = CreateWindowExW;

	decltype(&CreateWindowExW) CreateWindowExW__Hook = [](
		_In_     DWORD     dwExStyle,
		_In_opt_ LPCWSTR   lpClassName,
		_In_opt_ LPCWSTR   lpWindowName,
		_In_     DWORD     dwStyle,
		_In_     int       x,
		_In_     int       y,
		_In_     int       nWidth,
		_In_     int       nHeight,
		_In_opt_ HWND      hWndParent,
		_In_opt_ HMENU     hMenu,
		_In_opt_ HINSTANCE hInstance,
		_In_opt_ LPVOID    lpParam) -> HWND
	{
		HMODULE hModule;

		if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<TCHAR*>(_ReturnAddress()), &hModule))
		{
			if (hModule == GetModuleHandle(L"ava.exe"))
			{
				if (wcsstr(lpClassName, L"SPLASH"))
					return NULL;
			}
		}

		return _CreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
	};

	DetourFunction(TRUE, reinterpret_cast<LPVOID*>(&_CreateWindowExW), CreateWindowExW__Hook);
}

誤クリックの地味にウザいアレ

VOID Detour_ShellExecuteExW()
{
	static decltype(&ShellExecuteExW) _ShellExecuteExW = ShellExecuteExW;

	decltype(&ShellExecuteExW) ShellExecuteExW__Hook = [](
		_Inout_ SHELLEXECUTEINFO *pExecInfo) -> BOOL
	{
		if (pExecInfo && wcsstr(pExecInfo->lpFile, L"IEXPLORE.EXE"))
			return FALSE;

		return _ShellExecuteExW(pExecInfo);
	};

	DetourFunction(TRUE, reinterpret_cast<LPVOID*>(&_ShellExecuteExW), ShellExecuteExW__Hook);
}

ウィンドウフレーム以外からでもウィンドウを移動出来るようにする。

前回同じような記事を書いたのですが、継承するクラスによっては移動出来ない物もあったみたいですので、今回は nativeEvent関数をオーバーライドして実装してみました。

bool CMainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
	MSG *msg = reinterpret_cast<MSG*>(message);

	switch (msg->message)
	{
		case WM_LBUTTONDOWN:
		{
			if (!this->m_bClicked)
			{
				this->m_bClicked = true;
				this->m_originPos.setX(GET_X_LPARAM(msg->lParam));
				this->m_originPos.setY(GET_Y_LPARAM(msg->lParam));
			}
			break;
		}
		case WM_LBUTTONUP:
		{
			if (this->m_bClicked)
				this->m_bClicked = false;
			break;
		}
		case WM_MOUSEMOVE:
		{
			if (this->m_bClicked)
			{
				this->move(
					this->pos().x() + GET_X_LPARAM(msg->lParam) - this->m_originPos.x(),
					this->pos().y() + GET_Y_LPARAM(msg->lParam) - this->m_originPos.y());
			}
			break;
		}
		default:
			return QWidget::nativeEvent(eventType, message, result);
	}

	return false;
}

別プロセスのAPIのアドレスを取得する。

https://pastebin.com/QR1TUW7U

// GetProcessModuleInfo
ReadProcessMemoryで対象プロセスのPEBを読み取る -> モジュールの一覧取得 -> モジュールのベースアドレスの取得

// GetProcAddressEx
取得したモジュールのPEヘッダーからエクスポート関数のアドレス、名前、序数を列挙 -> 該当のアドレスを返す


プロセスとモジュールのメモリ共有型のアンチチート作ってみようと思って、モジュールのAPI/関数チェックに書いてみたけど、なんか微妙な感じに...また次触るときに書き直します。


全プロセスから xul.XRE_GetBootstrap (firefox), KERNELBASE.CreateFileW を列挙した画像です。
gyazo.com

QXmlStreamReader/Writerでxmlにウィジェットのステータスを保存する

サンプルコード

CConfigManager.hpp

#pragma once

#include <qwidget.h>
#include <map>

class CConfigManager
{
public:
	CConfigManager();
	~CConfigManager();

public:
	// 
	void WriteXmlElement(__in QXmlStreamWriter &writer);
	void ReadFromXml(__in QXmlStreamReader &reader);

	// for qwidget
	QCheckBox *CreateCheckBox(__in const QString &name, __in QWidget *parent = 0);
	QSpinBox *CreateSpinBox(__in const QString &name, __in QWidget *parent = 0);
	QLineEdit *CreateLineEdit(__in const QString &name, __in QWidget *parent = 0);
	QComboBox *CreateComboBox(__in const QString &name, __in QWidget *parent = 0);
	QPushButton *CreatePushButton(__in const QString &name, __in bool checkable, __in QWidget *parent = 0);
	QRadioButton *CreateRudioButton(__in const QString &name, __in QWidget *parent = 0);
	QSlider *CreateSlider(__in const QString &name, __in QWidget *parent = 0);

	static CConfigManager *GetInstance()
	{
		static CConfigManager instance;
		return &instance;
	}

private:
	void WriteXmlSettingsElement(__in QXmlStreamWriter &writer);
	void ReadXmlSettings(__in QXmlStreamReader &reader);

	void ReadXmlCheckBox(__in QXmlStreamReader &reader);
	void ReadXmlSpinBox(__in QXmlStreamReader &reader);
	void ReadXmlLineEdit(__in QXmlStreamReader &reader);
	void ReadXmlComboBox(__in QXmlStreamReader &reader);
	void ReadXmlPushButton(__in QXmlStreamReader &reader);
	void ReadXmlRadioButton(__in QXmlStreamReader &reader);
	void ReadXmlSlider(__in QXmlStreamReader &reader);

	// for qwidget
	std::map<QString, QCheckBox*> m_mCheckBox;
	std::map<QString, QSpinBox*> m_mSpinBox;
	std::map<QString, QLineEdit*> m_mLineEdit;
	std::map<QString, QComboBox*> m_mComboBox;
	std::map<QString, QPushButton*> m_mPushButton;
	std::map<QString, QRadioButton*> m_mRadioButton;
	std::map<QString, QSlider*> m_mSlider;
};

CConfigManager.cpp

#include "stdafx.h"

#include "CConfigManager.hpp"

CConfigManager::CConfigManager()
{
}

CConfigManager::~CConfigManager()
{
}

void CConfigManager::WriteXmlElement(__in QXmlStreamWriter &writer)
{
	// settings
	this->WriteXmlSettingsElement(writer);
}

void CConfigManager::WriteXmlSettingsElement(__in QXmlStreamWriter &writer)
{
	writer.writeStartElement("settings");

	foreach(auto it, this->m_mCheckBox)
	{
		if (it.second && it.first.size() > 1)
		{
			writer.writeStartElement("checkbox");
			writer.writeTextElement("name", it.first);
			writer.writeTextElement("state", QString::number(it.second->isChecked()));
			writer.writeEndElement();
		}
	}

	writer.writeEndElement();
}

void CConfigManager::ReadFromXml(__in QXmlStreamReader &reader)
{
	while (!reader.atEnd() && !reader.hasError())
	{
		QXmlStreamReader::TokenType token = reader.readNext();
		if (token == QXmlStreamReader::StartElement)
		{
			if (reader.name() == "settings")
			{
				// settings
				this->ReadXmlSettings(reader);
			}
		}
	}
}

void CConfigManager::ReadXmlSettings(__in QXmlStreamReader &reader)
{
	while (!reader.atEnd() && !reader.hasError())
	{
		QXmlStreamReader::TokenType token = reader.readNext();
		if (reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == "settings")
		{
			// element item end
			break;
		}
		if (token == QXmlStreamReader::StartElement)
		{
			if (reader.name() == "checkbox")
				this->ReadXmlCheckBox(reader);
		}
	}
}

void CConfigManager::ReadXmlCheckBox(__in QXmlStreamReader &reader)
{
	QString name = QString();
	while (!reader.atEnd() && !reader.hasError())
	{
		QXmlStreamReader::TokenType token = reader.readNext();
		if (reader.tokenType() == QXmlStreamReader::EndElement && reader.name() == "checkbox")
		{
			// element item end
			break;
		}
		if (token == QXmlStreamReader::StartElement)
		{
			if (reader.name() == "name")
				name = reader.readElementText();
			else if (reader.name() == "state" && name.length() > 1)
				this->m_mCheckBox[name]->setChecked(reader.readElementText().toInt());
		}
	}
}

// thanks to mahorori
QCheckBox *CConfigManager::CreateCheckBox(__in const QString &name, __in QWidget *parent)
{
	QCheckBox *checkBox = new QCheckBox(name, parent);
	this->m_mCheckBox[name] = checkBox;
	return checkBox;
}
//

...

使い方

CMainWindow::CMainWindow(__in QWidget *parent) : QMainWindow(parent)
{
        CConfigManager *pConfig = CConfigManager::GetInstance();
        QCheckBox *chkTestBox = pConfig->CreateCheckBox("Test Box");

        connect(chkTestBox, &QCheckBox::toggled, [=](bool toggled)
        {
                //
        }
        ...
}

void CMainWindow::OnLoad()
{
	QSettings settings;
	QString sFileName = QFileDialog::getOpenFileName(this, QString(), settings.value("filename").toString(), tr("Xml Files (*.xml)"));
	if (sFileName.isEmpty())
	{
		QMessageBox::warning(this, QString(), tr("Unknown error occurred."), QMessageBox::Ok);
		return;
	}

	QFile file(sFileName);
	if (!file.open(QIODevice::ReadOnly))
	{
		QMessageBox::warning(this, QString(), file.errorString(), QMessageBox::Ok);
		return;
	}

	CConfigManager::GetInstance()->ReadFromXml(QXmlStreamReader(&file));

	this->m_sXmlFileName = sFileName;
}

void CMainWindow::OnSave()
{
	if (this->m_sXmlFileName.isEmpty())
	{
		// no file exists, try to save as...
		this->OnSaveAs();
		return;
	}

	QFile file(this->m_sXmlFileName);
	if (!file.open(QIODevice::WriteOnly))
	{
		QMessageBox::warning(this, QString(), file.errorString(), QMessageBox::Ok);
		return;
	}

	QXmlStreamWriter writer(&file);
	writer.setAutoFormatting(true);
	writer.setAutoFormattingIndent(4);
	writer.writeStartDocument();

	// write elements
	writer.writeStartElement("XmlTester");
	CConfigManager::GetInstance()->WriteXmlElement(writer);
	writer.writeEndElement();

	file.close();

	QMessageBox::information(this, QString(), tr("Done."), QMessageBox::Ok);
}

void CMainWindow::OnSaveAs()
{
	//
	QString sFileName = QFileDialog::getSaveFileName(this, QString(), QString(), tr("Xml Files (*.xml)"));
	if (sFileName.isEmpty())
	{
		// QMessageBox::warning(this, QString(), tr("Unknown error occurred."), QMessageBox::Ok);
		return;
	}

	this->m_sXmlFileName = sFileName;
	this->OnSave();
}