jane_style_ad_block.zip/jane_style_ad_block/main.cpp
#include <iostream>
#include <iterator>
#include <string>
#include <boost/version.hpp>
#include <boost/static_assert.hpp>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <boost/range/irange.hpp>
#include <Windows.h>
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#include <winhttp.h>
#pragma comment(lib, "Winhttp.lib")
#include <wincrypt.h>
//#include <org/click3/dll_hack_lib.h>
HINTERNET authRequest = NULL;
const HINTERNET futenRequest = reinterpret_cast<HINTERNET>(0x45678900);
bool futenAvailable = false;
HINTERNET __stdcall d_WinHttpConnect(HINTERNET hSession, LPCWSTR pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved) {
std::wcout << L"WinHttpConnect\n";
std::wcout << pswzServerName << std::endl;
return ::WinHttpConnect(hSession, pswzServerName, nServerPort, dwReserved);
}
HINTERNET __stdcall d_WinHttpOpenRequest(HINTERNET hConnect, LPCWSTR pwszVerb, LPCWSTR pwszObjectName, LPCWSTR pwszVersion, LPCWSTR pwszReferrer, LPCWSTR *ppwszAcceptTypes, DWORD dwFlags) {
std::wcout << L"WinHttpOpenRequest\n";
std::wcout << pwszObjectName << std::endl;
if (std::wstring(L"/futen.cgi") == pwszObjectName) {
futenAvailable = true;
return futenRequest;
}
const HINTERNET result = ::WinHttpOpenRequest(hConnect, pwszVerb, pwszObjectName, pwszVersion, pwszReferrer, ppwszAcceptTypes, dwFlags);
if (std::wstring(L"/v1/auth/") == pwszObjectName) {
authRequest = result;
}
return result;
}
BOOL __stdcall d_WinHttpQueryDataAvailable(HINTERNET hRequest, LPDWORD lpdwNumberOfBytesAvailable) {
std::wcout << L"WinHttpQueryDataAvailable\n";
if (hRequest == futenRequest) {
if (futenAvailable) {
*lpdwNumberOfBytesAvailable = 204;
} else {
*lpdwNumberOfBytesAvailable = 0;
}
return TRUE;
}
const BOOL result = ::WinHttpQueryDataAvailable(hRequest, lpdwNumberOfBytesAvailable);
std::wcout << *lpdwNumberOfBytesAvailable << std::endl;
return result;
}
BOOL __stdcall d_WinHttpReadData(HINTERNET hRequest, LPVOID lpBuffer, DWORD dwNumberOfBytesToRead, LPDWORD lpdwNumberOfBytesRead) {
static char sessionId[204] = {};
std::wcout << L"WinHttpReadData\n";
char * const buf = reinterpret_cast<char *>(lpBuffer);
if (authRequest == hRequest && dwNumberOfBytesToRead == 203) {
const BOOL result = ::WinHttpReadData(hRequest, sessionId, _countof(sessionId), lpdwNumberOfBytesRead);
std::cout << std::string(&sessionId[0], &sessionId[*lpdwNumberOfBytesRead]) << std::endl;
std::copy(&sessionId[0], &sessionId[*lpdwNumberOfBytesRead], stdext::checked_array_iterator<char *>(buf, dwNumberOfBytesToRead));
return result;
}
if (futenRequest != hRequest || dwNumberOfBytesToRead != _countof(sessionId)) {
return ::WinHttpReadData(hRequest, buf, dwNumberOfBytesToRead, lpdwNumberOfBytesRead);
}
futenAvailable = false;
*lpdwNumberOfBytesRead = _countof(sessionId);
std::copy(&sessionId[0], &sessionId[_countof(sessionId)], stdext::checked_array_iterator<char *>(buf, _countof(sessionId)));
std::cout << std::string(&sessionId[0], &sessionId[*lpdwNumberOfBytesRead]) << std::endl;
return TRUE;
}
BOOL __stdcall d_WinHttpSetTimeouts(HINTERNET hInternet, int nResolveTimeout, int nConnectTimeout, int nSendTimeout, int nReceiveTimeout) {
std::wcout << L"WinHttpSetTimeouts\n";
if (futenRequest == hInternet) {
return TRUE;
}
return ::WinHttpSetTimeouts(hInternet, 2000, 2000, 2000, 2000);
}
BOOL __stdcall d_WinHttpSetCredentials(HINTERNET hRequest, DWORD AuthTargets, DWORD AuthScheme, LPCWSTR pwszUserName, LPCWSTR pwszPassword, LPVOID pAuthParams) {
std::wcout << L"WinHttpSetCredentials\n";
if (futenRequest == hRequest) {
return TRUE;
}
return ::WinHttpSetCredentials(hRequest, AuthTargets, AuthScheme, pwszUserName, pwszPassword, pAuthParams);
}
BOOL __stdcall d_WinHttpSendRequest(HINTERNET hRequest, LPCWSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext) {
std::wcout << L"WinHttpSendRequest\n";
std::wcout << lpszHeaders << std::endl;
std::cout << reinterpret_cast<const char *>(lpOptional) << std::endl;
if (futenRequest == hRequest) {
return TRUE;
}
return ::WinHttpSendRequest(hRequest, lpszHeaders, dwHeadersLength, lpOptional, dwOptionalLength, dwTotalLength, dwContext);
}
BOOL __stdcall d_WinHttpReceiveResponse(HINTERNET hRequest, LPVOID lpReserved) {
std::wcout << L"WinHttpReceiveResponse\n";
if (futenRequest == hRequest) {
return TRUE;
}
return ::WinHttpReceiveResponse(hRequest, lpReserved);
}
BOOL __stdcall d_WinHttpQueryHeaders(HINTERNET hRequest, DWORD dwInfoLevel, LPCWSTR pwszName, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) {
std::wcout << L"WinHttpQueryHeaders\n";
if (futenRequest == hRequest) {
if ((WINHTTP_QUERY_FLAG_NUMBER | WINHTTP_QUERY_STATUS_CODE) == dwInfoLevel) {
*reinterpret_cast<unsigned int *>(lpBuffer) = 200;
return TRUE;
}
if (WINHTTP_QUERY_RAW_HEADERS_CRLF == dwInfoLevel) {
static const wchar_t headers[] =
L"HTTP/1.1 200 OK\r\n"
L"Connection: close\r\n"
L"Content-Length: 204\r\n"
L"Content-Type: text/plain\r\n"
L"Server: Apache/2.2.15 (Unix) mod_ssl/2.2.15 OpenSSL/0.9.8n PHP/5.2.13\r\n"
L"Vary: Accept-Encoding\r\n"
L"X-Powered-By: PHP/5.2.13\r\n\r\n";
if (lpBuffer == nullptr) {
*lpdwBufferLength = sizeof(headers);
::SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
std::copy(&headers[0], &headers[_countof(headers)], stdext::checked_array_iterator<wchar_t *>(reinterpret_cast<wchar_t *>(lpBuffer), *lpdwBufferLength));
return TRUE;
}
return FALSE;
}
return ::WinHttpQueryHeaders(hRequest, dwInfoLevel, pwszName, lpBuffer, lpdwBufferLength, lpdwIndex);
}
BOOL __stdcall d_WinHttpCloseHandle(HINTERNET hInternet) {
std::wcout << L"WinHttpCloseHandle\n";
if (futenRequest == hInternet) {
return TRUE;
}
return ::WinHttpCloseHandle(hInternet);
}
std::string getAccountCfgPath() {
char filename[MAX_PATH];
::GetModuleFileNameA(NULL, filename, sizeof(filename));
::PathRemoveFileSpecA(filename);
::PathAppendA(filename, "account.cfg");
return filename;
}
const HANDLE FIND_FILE_HANDLE_ACCOUNT_CFG = reinterpret_cast<HANDLE>(0x12345678);
const HANDLE FILE_HANDLE_ACCOUNT_CFG = reinterpret_cast<HANDLE>(0x23456789);
const char ACCOUNT_CFG_BODY[] = R"([RONIN]
UserID=dummy_id
Passwd=jAAAAAECAAACZgAAAKQAAEEu1+zneRKFw4kADrU8qOL96GlFjFktBZcIHHnKOR8hhGMnL7KDtAZ4jgC5t7Bnw0QfdVbB0fDAoWvfTNNOsYv4tXOB24pboFuAx9t4Nhxy+mjtDG4fApO3p2coum5yWJrEsRAnLKsv/wpjSHwVPcuimRhKmrmboDvTAwlCfa9OXDJ0gApOulM=
ALT=
AutoLogin=1
WriteLogin=0
)";
unsigned int ACCOUNT_CFG_POS = 0;
HANDLE __stdcall d_FindFirstFileA(const char * const lpFileName, WIN32_FIND_DATAA * const lpFindFileData) {
if (getAccountCfgPath() == lpFileName) {
SYSTEMTIME st;
::GetSystemTime(&st);
WIN32_FIND_DATAA &fd = *lpFindFileData;
fd.dwFileAttributes = FILE_ATTRIBUTE_READONLY;
::SystemTimeToFileTime(&st, &fd.ftCreationTime);
::SystemTimeToFileTime(&st, &fd.ftLastAccessTime);
::SystemTimeToFileTime(&st, &fd.ftLastWriteTime);
fd.nFileSizeLow = sizeof(ACCOUNT_CFG_BODY);
std::copy(&lpFileName[0], &lpFileName[::strlen(lpFileName)], stdext::checked_array_iterator<char *>(fd.cFileName, _countof(fd.cFileName)));
return FIND_FILE_HANDLE_ACCOUNT_CFG;
}
return ::FindFirstFileA(lpFileName, lpFindFileData);
}
BOOL __stdcall d_FindClose(HANDLE hFindFile) {
if (hFindFile == FIND_FILE_HANDLE_ACCOUNT_CFG) {
return TRUE;
}
return FindClose(hFindFile);
}
HANDLE __stdcall d_CreateFileA(
const char * const lpFileName,
const DWORD dwDesiredAccess,
const DWORD dwShareMode,
SECURITY_ATTRIBUTES * const lpSecurityAttributes,
const DWORD dwCreationDisposition,
const DWORD dwFlagsAndAttributes,
const HANDLE hTemplateFile)
{
if (getAccountCfgPath() == lpFileName && dwDesiredAccess == GENERIC_READ) {
ACCOUNT_CFG_POS = 0;
return FILE_HANDLE_ACCOUNT_CFG;
}
return ::CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
BOOL __stdcall d_CloseHandle(const HANDLE handle) {
if (handle == FILE_HANDLE_ACCOUNT_CFG) {
return TRUE;
}
return ::CloseHandle(handle);
}
BOOL __stdcall d_ReadFile(const HANDLE hFile, void * const lpBuffer, const DWORD nNumberOfBytesToRead, DWORD * const lpNumberOfBytesRead, OVERLAPPED * const lpOverlapped) {
if (hFile != FILE_HANDLE_ACCOUNT_CFG) {
return ::ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
}
const unsigned int readSize = (std::min)(static_cast<unsigned int>(nNumberOfBytesToRead), sizeof(ACCOUNT_CFG_BODY) - ACCOUNT_CFG_POS);
std::copy(
&ACCOUNT_CFG_BODY[ACCOUNT_CFG_POS],
&ACCOUNT_CFG_BODY[ACCOUNT_CFG_POS + readSize],
stdext::checked_array_iterator<char *>(reinterpret_cast<char *>(lpBuffer), nNumberOfBytesToRead));
if (lpNumberOfBytesRead != NULL) {
*lpNumberOfBytesRead = readSize;
}
ACCOUNT_CFG_POS += readSize;
return TRUE;
}
DWORD __stdcall d_SetFilePointer(const HANDLE hFile, const LONG lDistanceToMove, LONG * const lpDistanceToMoveHigh, const DWORD dwMoveMethod) {
if (hFile != FILE_HANDLE_ACCOUNT_CFG) {
return ::SetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod);
}
long long int distance = 0;
if (lpDistanceToMoveHigh == nullptr) {
distance = lDistanceToMove;
} else {
distance = static_cast<unsigned int>(lDistanceToMove) | (static_cast<long long int>(*lpDistanceToMoveHigh) << 32);
}
long long int cur = ACCOUNT_CFG_POS;
long long int size = sizeof(ACCOUNT_CFG_BODY);
unsigned long long int ptr = 0;
switch (dwMoveMethod) {
case FILE_BEGIN:
ptr = (std::max)((std::min)(distance, size), 0LL);
break;
case FILE_CURRENT:
ptr = (std::max)((std::min)(cur + distance, size), 0LL);
break;
case FILE_END:
ptr = (std::max)((std::min)(size + distance, size), 0LL);
break;
default:
return FALSE;
}
ACCOUNT_CFG_POS = static_cast<unsigned int>(ptr);
if (lpDistanceToMoveHigh != NULL) {
*lpDistanceToMoveHigh = (ptr >> 32);
}
return static_cast<DWORD>(ptr);
}
FARPROC __stdcall d_GetProcAddress(HMODULE hModule, LPCSTR lpProcName) {
struct ProcMap {
std::string name;
const FARPROC proc;
};
static const std::vector<ProcMap> list = {
{"WinHttpConnect", reinterpret_cast<FARPROC>(d_WinHttpConnect) },
{"WinHttpOpenRequest", reinterpret_cast<FARPROC>(d_WinHttpOpenRequest) },
{"WinHttpQueryDataAvailable", reinterpret_cast<FARPROC>(d_WinHttpQueryDataAvailable) },
{"WinHttpReadData", reinterpret_cast<FARPROC>(d_WinHttpReadData) },
{"WinHttpSetTimeouts", reinterpret_cast<FARPROC>(d_WinHttpSetTimeouts) },
{"WinHttpSetCredentials", reinterpret_cast<FARPROC>(d_WinHttpSetCredentials) },
{"WinHttpSendRequest", reinterpret_cast<FARPROC>(d_WinHttpSendRequest) },
{"WinHttpReceiveResponse", reinterpret_cast<FARPROC>(d_WinHttpReceiveResponse) },
{"WinHttpQueryHeaders", reinterpret_cast<FARPROC>(d_WinHttpQueryHeaders) },
{"WinHttpCloseHandle", reinterpret_cast<FARPROC>(d_WinHttpCloseHandle) },
};
const auto it = std::find_if(list.begin(), list.end(), [lpProcName](const auto item) { return item.name == lpProcName; });
if (it == list.end()) {
return ::GetProcAddress(hModule, lpProcName);
}
return it->proc;
}
const HCRYPTKEY CRYPT_KEY_HANDLE_DUMMY = 0x34567890U;
BOOL __stdcall d_CryptImportKey(HCRYPTPROV hProv, const BYTE *pbData, DWORD dwDataLen, HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY *phKey) {
const BOOL result = ::CryptImportKey(hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey);
if (result == FALSE) {
*phKey = CRYPT_KEY_HANDLE_DUMMY;
return TRUE;
}
return result;
}
BOOL __stdcall d_CryptDecrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen) {
if (hKey != CRYPT_KEY_HANDLE_DUMMY) {
return ::CryptDecrypt(hKey, hHash, Final, dwFlags, pbData, pdwDataLen);
}
const char password[] = "a";
std::copy(&password[0], &password[_countof(password)], stdext::checked_array_iterator<BYTE *>(pbData, *pdwDataLen));
*pdwDataLen = ::strlen(password);
return TRUE;
}
BOOL __stdcall d_CryptDestroyKey(HCRYPTKEY hKey) {
if (hKey == CRYPT_KEY_HANDLE_DUMMY) {
return TRUE;
}
return ::CryptDestroyKey(hKey);
}
bool ChangeIAT(HMODULE module) {
static const struct {
const std::string dllName;
const std::string procName;
const unsigned int procAddress;
} targetList[] = {
{ "KERNEL32.dll", "FindFirstFileA", reinterpret_cast<unsigned int>(d_FindFirstFileA) },
{ "KERNEL32.dll", "FindClose", reinterpret_cast<unsigned int>(d_FindClose) },
{ "KERNEL32.dll", "CreateFileA", reinterpret_cast<unsigned int>(d_CreateFileA) },
{ "KERNEL32.dll", "CloseHandle", reinterpret_cast<unsigned int>(d_CloseHandle) },
{ "KERNEL32.dll", "ReadFile", reinterpret_cast<unsigned int>(d_ReadFile) },
{ "KERNEL32.dll", "SetFilePointer", reinterpret_cast<unsigned int>(d_SetFilePointer) },
{ "KERNEL32.dll", "GetProcAddress", reinterpret_cast<unsigned int>(d_GetProcAddress) },
{ "ADVAPI32.dll", "CryptDecrypt", reinterpret_cast<unsigned int>(d_CryptDecrypt) },
{ "ADVAPI32.dll", "CryptImportKey", reinterpret_cast<unsigned int>(d_CryptImportKey) },
{ "ADVAPI32.dll", "CryptDestroyKey", reinterpret_cast<unsigned int>(d_CryptDestroyKey) },
};
unsigned char * const baseAddr = reinterpret_cast<unsigned char *>(module == NULL ? ::GetModuleHandleW(NULL) : module);
const IMAGE_DOS_HEADER &mz = *reinterpret_cast<const IMAGE_DOS_HEADER *>(baseAddr);
const IMAGE_NT_HEADERS32 &pe = *reinterpret_cast<const IMAGE_NT_HEADERS32 *>(baseAddr + mz.e_lfanew);
const IMAGE_IMPORT_DESCRIPTOR *desc = reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR *>(baseAddr + pe.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
if (desc->OriginalFirstThunk == 0) { // IATがない場合
struct AddressMapItem {
unsigned int original;
unsigned int dummy;
};
std::vector<AddressMapItem> addressMap(_countof(targetList));
for (const unsigned int i : boost::irange(0U, _countof(targetList))) {
const auto &target = targetList[i];
addressMap[i].original = reinterpret_cast<unsigned int>(::GetProcAddress(::GetModuleHandleA(target.dllName.c_str()), target.procName.c_str()));
addressMap[i].dummy = target.procAddress;
}
for (; desc->Name != 0; desc++) {
const char * const dllName = reinterpret_cast<const char *>(baseAddr + desc->Name);
unsigned int *out = reinterpret_cast<unsigned int *>(baseAddr + desc->FirstThunk);
for (; *out != 0; out++) {
const auto it = std::find_if(addressMap.begin(), addressMap.end(), [out](const auto item) {
return item.original == *out;
});
if (it != addressMap.end()) {
DWORD oldProtect;
::VirtualProtect(out, 4, PAGE_READWRITE, &oldProtect);
*out = it->dummy;
::VirtualProtect(out, 4, oldProtect, &oldProtect);
}
}
}
return true;
}
for (; desc->OriginalFirstThunk != 0; desc = ++desc) {
const char * const dllName = reinterpret_cast<const char *>(baseAddr + desc->Name);
const unsigned int *in = reinterpret_cast<unsigned int *>(baseAddr + desc->OriginalFirstThunk);
unsigned int *out = reinterpret_cast<unsigned int *>(baseAddr + desc->FirstThunk);
for (; *in != 0; ++in, ++out) {
if ((*in & 0x80000000) != 0) {
continue;
}
const char * const procName = reinterpret_cast<const char *>(baseAddr + *in + 2);
for (const auto &target : targetList) {
if (::_stricmp(target.dllName.c_str(), dllName) != 0 || target.procName != procName) {
continue;
}
DWORD oldProtect;
::VirtualProtect(out, 4, PAGE_READWRITE, &oldProtect);
*out = target.procAddress;
::VirtualProtect(out, 4, oldProtect, &oldProtect);
}
}
}
return true;
}
void main() {
//::org::click3::DllHackLib::SetupConsole();
ChangeIAT(NULL);
}