Created
July 8, 2019 03:14
-
-
Save hyrious/94b0126cdf12239af73d9afabb29a080 to your computer and use it in GitHub Desktop.
Sample RGSS Console Using MailSlot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# coding: utf-8 | |
Font.default_name = ['等距更纱黑体 SC', '等线', 'SimHei'] | |
class Module | |
public :include | |
end | |
if defined? Graphics.background_exec | |
Graphics.background_exec = true | |
else | |
# RGSS103J 0x2E48 \x46 | |
# RGSS102J 100J 0x2E09 \x46 | |
# RGSS104E 0x4FA4 \x5F | |
# RGSS200J 200E 202E 0x19AA \x35 | |
# RGSS300 301 0x2712 \x5A | |
WriteProcessMemory = Win32API.new('kernel32','WriteProcessMemory','llpll','l') | |
DLL=Win32API.new('kernel32','LoadLibrary','p','l').call('RGSS301') | |
WriteProcessMemory.call(-1,DLL+0x2712,"\0",1,0) | |
end | |
class Api | |
def initialize dll, func | |
@dll, @func = dll.to_s, func.to_s | |
@instance = nil | |
end | |
def call *args | |
@comment = "#{@func}.call(#{args.map(&:inspect).join(', ')})" | |
# puts @comment | |
(@instance ||= create_instance(*args)).call(*args) | |
end | |
def create_instance *args | |
@imports = args.map { |e| Integer === e ? 'L' : 'p' } | |
Win32API.new(@dll, @func, @imports, 'i') | |
end | |
def declaration | |
return '' unless @instance and @comment | |
imports = @imports.empty? ? 'v' : @imports.join | |
[ ["# ", @comment].join, | |
["#{@func} = ", | |
"Win32API.new(#{@dll.inspect}, ", | |
"#{@func.inspect}, ", | |
"#{imports.inspect}, 'i')"].join | |
].join("\n") | |
end | |
class Dll | |
def initialize dll | |
@dll = dll | |
end | |
def method_missing func, *args | |
Api.callapi @dll, func, *args | |
end | |
end | |
def self.callapi dll, name, *args | |
((@_win32api ||= {})[[dll, name]] ||= Api.new(dll, name)).call(*args) | |
end | |
def self.export_apis | |
return unless @_win32api | |
puts | |
@_win32api.each do |(dll, name), api| | |
puts api.declaration | |
end | |
puts | |
end | |
def self.method_missing dll | |
Dll.new dll | |
end | |
end | |
class MailSlot | |
def self.create | |
new "\\\\.\\mailslot\\rgss_#{$$}_#{rand(0x100000000).to_s(36)}" | |
end | |
MAILSLOT_NO_MESSAGE = MAILSLOT_WAIT_FOREVER = INVALID_HANDLE_VALUE = -1 | |
def initialize name | |
@name = name | |
@handle = Api.kernel32.CreateMailslot name, 0, MAILSLOT_WAIT_FOREVER, 0 | |
@disposed = false | |
if @handle == INVALID_HANDLE_VALUE | |
puts "CreateMailslot failed with #{Api.kernel32.GetLastError()}." | |
@disposed = true | |
end | |
end | |
attr_reader :name, :handle | |
def disposed? | |
@disposed | |
end | |
FALSE = 0 | |
def dispose | |
@disposed = true | |
if Api.kernel32.CloseHandle(@handle) == FALSE | |
puts "CloseHandle failed with #{Api.kernel32.GetLastError()}." | |
end | |
end | |
def read | |
result = [] | |
return result if disposed? | |
event = Api.kernel32.CreateEvent(0, 0, 0, 0) | |
if event == 0 | |
puts "CreateEvent failed with #{Api.kernel32.GetLastError()}." | |
return result | |
end | |
ov = [0, 0, 0, 0, event].pack('L5') | |
next_len = [0].pack('L') | |
count = [0].pack('L') | |
ret = Api.kernel32.GetMailslotInfo(@handle, 0, next_len, count, 0) | |
if ret == FALSE | |
puts "GetMailslotInfo failed with #{Api.kernel32.GetLastError()}." | |
return result | |
end | |
if next_len == MAILSLOT_NO_MESSAGE | |
return result | |
end | |
while count.unpack('L')[0] > 0 | |
size = next_len.unpack('L')[0] | |
read = [0].pack('L') | |
# should it cause error, use GlobalAlloc(0x40, next_len.unpack('L')[0]) | |
buffer = [].pack("x#{size}") | |
ret = Api.kernel32.ReadFile(@handle, buffer, size, read, ov) | |
if ret == FALSE | |
puts "ReadFile failed with #{Api.kernel32.GetLastError()}." | |
return result | |
end | |
result << buffer.unpack('Z*')[0] | |
ret = Api.kernel32.GetMailslotInfo(@handle, 0, next_len, count, 0) | |
if ret == FALSE | |
puts "GetMailslotInfo failed with #{Api.kernel32.GetLastError()}." | |
return result | |
end | |
end | |
if Api.kernel32.CloseHandle(event) == FALSE | |
puts "CloseHandle failed with #{Api.kernel32.GetLastError()}." | |
end | |
result | |
end | |
def pop | |
(@queue ||= []).push(*read).shift | |
end | |
def self.write name, message | |
handle = (@_clients ||= {})[name] ||= open(name) | |
written = [0].pack('L') | |
msg = [message].pack('Z*') | |
ret = Api.kernel32.WriteFile(handle, msg, msg.size, written, 0) | |
if ret == FALSE | |
puts "WriteFile failed with #{Api.kernel32.GetLastError()}." | |
end | |
end | |
def self.open name | |
handle = Api.kernel32.CreateFile(name, 0x40000000, 1, 0, 3, 0x80, 0) | |
if handle == INVALID_HANDLE_VALUE | |
puts "CreateFile failed with #{Api.kernel32.GetLastError()}." | |
end | |
handle | |
end | |
def self.dispose | |
@_clients.each_value { |handle| Api.kernel32.CloseHandle handle } | |
@_clients.clear | |
end | |
end | |
SlotServer = MailSlot.create | |
Api.shell32.ShellExecute 0, 0, 'Scripts\sample_console.exe', SlotServer.name, 0, 1 | |
Graphics.update until client = SlotServer.pop | |
MailSlot.write client, "OK" | |
loop do | |
if msg = SlotServer.pop | |
puts "=> #{msg}".chomp | |
ret = 'nil' | |
begin | |
ret = eval(msg, TOPLEVEL_BINDING).inspect | |
rescue SystemExit | |
break | |
rescue Exception => e | |
ret = "#{e.class}: #{e}" | |
end | |
puts ">> #{ret}".chomp | |
MailSlot.write client, ret | |
end | |
Graphics.update | |
end | |
SlotServer.dispose | |
MailSlot.dispose | |
Api.export_apis |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <windows.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#include <string.h> | |
/* -fgnu89-inline */ | |
#include <strsafe.h> | |
HANDLE hSlotServer, hSlotClient; | |
TCHAR SlotServer[80], SlotClient[80]; | |
char tmp[10], template[] = "0123456789abcdefghijklmnopqrstuvwxyz"; | |
BOOL RandSlotServerName(void) { | |
srand(time(0)); | |
UINT i = (UINT) (((double) rand() / RAND_MAX) * INT_MAX); | |
int j = 0; | |
do { | |
tmp[j++] = template[i % 36]; | |
i /= 36; | |
} while (i); | |
HRESULT fResult = StringCbPrintf(SlotServer, sizeof(SlotServer), TEXT("\\\\.\\mailslot\\rgss_%d_%s"), GetCurrentProcessId(), tmp); | |
if (SUCCEEDED(fResult)) { | |
return TRUE; | |
} else { | |
printf("StringCbPrintf failed with (HRESULT) %d.\n", fResult); | |
printf("See https://docs.microsoft.com/en-us/windows/win32/api/strsafe/nf-strsafe-stringcbprintfa for more details.\n"); | |
return FALSE; | |
} | |
} | |
BOOL GetSlotClientName(char *cmd) { | |
HRESULT fResult = StringCbCopy(SlotClient, sizeof(SlotClient), cmd); | |
if (SUCCEEDED(fResult)) { | |
return TRUE; | |
} else { | |
printf("StringCbCopy failed with (HRESULT) %d.\n", fResult); | |
printf("See https://docs.microsoft.com/en-us/windows/win32/api/strsafe/nf-strsafe-stringcbcopya for more details.\n"); | |
return FALSE; | |
} | |
} | |
BOOL MakeSlotServer(LPTSTR lpszSlotName) { | |
hSlotServer = CreateMailslot(lpszSlotName, 0, MAILSLOT_WAIT_FOREVER, 0); | |
if (hSlotServer == INVALID_HANDLE_VALUE) { | |
printf("CreateMailslot failed with %d.\n", GetLastError()); | |
return FALSE; | |
} | |
return TRUE; | |
} | |
BOOL GetSlotClient(LPTSTR lpszSlotName) { | |
hSlotClient = CreateFile(lpszSlotName, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); | |
if (hSlotClient == INVALID_HANDLE_VALUE) { | |
printf("CreateFile failed with %d.\n", GetLastError()); | |
return FALSE; | |
} | |
return TRUE; | |
} | |
BOOL ReadSlotServer(void) { | |
DWORD cbMessage, cMessage, cbRead; | |
BOOL fResult; | |
LPTSTR lpszBuffer; | |
TCHAR achID[80]; | |
DWORD cAllMessages; | |
HANDLE hEvent; | |
OVERLAPPED ov; | |
cbMessage = cMessage = cbRead = 0; | |
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); | |
ov.Offset = ov.OffsetHigh = 0; | |
ov.hEvent = hEvent; | |
fResult = GetMailslotInfo(hSlotServer, 0, &cbMessage, &cMessage, 0); | |
if (!fResult) { | |
printf("GetMailslotInfo failed with %d.\n", GetLastError()); | |
return FALSE; | |
} | |
if (cbMessage == MAILSLOT_NO_MESSAGE) { | |
// printf("waiting...\n"); | |
return TRUE; | |
} | |
cAllMessages = cMessage; | |
while (cMessage) { | |
lpszBuffer = (LPTSTR) GlobalAlloc(GPTR, cbMessage); | |
if (lpszBuffer == NULL) | |
return FALSE; | |
lpszBuffer[0] = '\0'; | |
fResult = ReadFile(hSlotServer, lpszBuffer, cbMessage, &cbRead, &ov); | |
if (!fResult) { | |
printf("ReadFile failed with %d.\n", GetLastError()); | |
GlobalFree((HGLOBAL) lpszBuffer); | |
return FALSE; | |
} | |
printf("=> %s\n>> ", lpszBuffer); | |
GlobalFree((HGLOBAL) lpszBuffer); | |
fResult = GetMailslotInfo(hSlotServer, 0, &cbMessage, &cMessage, 0); | |
if (!fResult) { | |
printf("GetMailslotInfo failed with %d.\n", GetLastError()); | |
return FALSE; | |
} | |
} | |
CloseHandle(hEvent); | |
return TRUE; | |
} | |
BOOL WriteSlotClient(LPTSTR lpszMessage) { | |
BOOL fResult; | |
DWORD cbWritten; | |
fResult = WriteFile(hSlotClient, lpszMessage, (lstrlen(lpszMessage) + 1) * sizeof(TCHAR), &cbWritten, 0); | |
if (!fResult) { | |
printf("WriteFile failed with %d.\n", GetLastError()); | |
return FALSE; | |
} | |
return TRUE; | |
} | |
DWORD WINAPI ServerThread(LPVOID lpParam) { | |
while (ReadSlotServer()) { | |
Sleep(100); | |
} | |
return 0; | |
} | |
#define CONSOLE_BUFFER_SIZE 1024 | |
TCHAR szBuffer[CONSOLE_BUFFER_SIZE]; | |
int main(int argc, char **argv) { | |
if (argc == 1) { | |
printf("usage: %s \\\\.\\mailslot\\<rgss-slot-server-name>\n", argv[0]); | |
return 0; | |
} | |
SetConsoleTitle(TEXT("Sample Console")); | |
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); | |
DWORD dwMode; | |
if (GetConsoleMode(hOutput, &dwMode)) { | |
SetConsoleMode(hOutput, dwMode | ENABLE_ECHO_INPUT); | |
} | |
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE); | |
DWORD dwRead; | |
if (GetSlotClientName(argv[1]) && RandSlotServerName()) { | |
printf("\n> client: %s\n> server: %s\n\n", SlotClient, SlotServer); | |
} else { | |
return EXIT_FAILURE; | |
} | |
if (!MakeSlotServer(SlotServer)) { | |
return EXIT_FAILURE; | |
} | |
if (!GetSlotClient(SlotClient)) { | |
return EXIT_FAILURE; | |
} | |
WriteSlotClient(SlotServer); | |
DWORD dwThreadId; | |
HANDLE hThread = CreateThread(NULL, 0, ServerThread, NULL, 0, &dwThreadId); | |
while (TRUE) { | |
ZeroMemory(szBuffer, CONSOLE_BUFFER_SIZE); | |
if (ReadConsole(hInput, szBuffer, CONSOLE_BUFFER_SIZE, &dwRead, NULL)) { | |
WriteSlotClient(szBuffer); | |
if (strncmp(szBuffer, "exit", 4) == 0) { | |
break; | |
} | |
} else { | |
printf("ReadConsole failed with %d.\n", GetLastError()); | |
} | |
} | |
TerminateThread(hThread, 0); | |
CloseHandle(hSlotClient); | |
CloseHandle(hSlotServer); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment