Skip to content

Instantly share code, notes, and snippets.

@yuru4c
Last active June 16, 2018 01:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yuru4c/3720701323878f88be909b458b4f2f85 to your computer and use it in GitHub Desktop.
Save yuru4c/3720701323878f88be909b458b4f2f85 to your computer and use it in GitHub Desktop.
艦これ Flash 一時停止プログラムの断片
using System;
using System.Diagnostics;
using System.Windows.Forms;
using Suspender.Utility;
namespace Suspender
{
internal partial class FormSuspender : Form
{
private const int PseudoId = -1;
private readonly FormBrowser _browser;
private int _video = PseudoId;
private int _sound = PseudoId;
internal FormSuspender(FormBrowser browser)
{
_browser = browser;
InitializeComponent();
}
private void Suspend()
{
_video = PseudoId;
_sound = PseudoId;
try
{
using (var snapshot = new Api.Snapshot(
Process.GetProcessById(_browser.BrowserProcess.Id)))
{
const string moduleName = "Flash.ocx";
var video = snapshot.GetLastThreadId(moduleName, 8);
Api.SuspendThread(video);
_video = video;
try
{
var sound = snapshot.GetLastThreadId(moduleName, 21);
Api.SuspendThread(sound);
_sound = sound;
}
catch
{
}
}
}
catch
{
return;
}
}
private void Resume()
{
if (_video != PseudoId)
{
try
{
Api.ResumeThread(_video);
}
catch
{
}
}
if (_sound != PseudoId)
{
try
{
Api.ResumeThread(_sound);
}
catch
{
}
}
}
}
}
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Suspender.Utility
{
internal static partial class Api
{
#region Private
private static IntPtr OpenThread(int threadId, NativeMethods.ThreadAccess threadAccess)
{
var hThread = NativeMethods.OpenThread(threadAccess, false, (uint)threadId);
if (hThread == IntPtr.Zero)
{
throw new Win32Exception();
}
return hThread;
}
private static uint SuspendThread(IntPtr hThread)
{
var result = NativeMethods.SuspendThread(hThread);
if ((int)result == -1)
{
throw new Win32Exception();
}
return result;
}
private static uint ResumeThread(IntPtr hThread)
{
var result = NativeMethods.ResumeThread(hThread);
if ((int)result == -1)
{
throw new Win32Exception();
}
return result;
}
private static IntPtr CreateModuleSnapshot(int processId)
{
var snapshot = NativeMethods.CreateToolhelp32Snapshot(
NativeMethods.Th32Cs.SnapModule | NativeMethods.Th32Cs.SnapModule32,
(uint)processId);
if ((int)snapshot == -1)
{
throw new Win32Exception();
}
return snapshot;
}
private static string GetThreadModuleName(IntPtr snapshot, int threadId)
{
var mod = new NativeMethods.ModuleEntry32
{
dwSize = (uint)Marshal.SizeOf(typeof(NativeMethods.ModuleEntry32))
};
if (!NativeMethods.Module32First(snapshot, ref mod))
{
return null;
}
var startAddress = GetThreadStartAddress(threadId);
do
{
var modBaseAddr = (ulong)mod.modBaseAddr;
if (startAddress >= modBaseAddr)
{
if (startAddress < modBaseAddr + mod.modBaseSize)
{
return mod.szModule;
}
}
} while (NativeMethods.Module32Next(snapshot, ref mod));
return null;
}
private static ulong GetThreadStartAddress(int threadId)
{
var threadHandle = OpenThread(threadId, NativeMethods.ThreadAccess.QueryInformation);
try
{
var threadInformation = Marshal.AllocHGlobal(IntPtr.Size);
try
{
var ntstatus = NativeMethods.NtQueryInformationThread(threadHandle,
NativeMethods.ThreadInfoClass.ThreadQuerySetWin32StartAddress,
threadInformation, (uint)IntPtr.Size, IntPtr.Zero);
if (ntstatus != 0U)
{
throw new Exception();
}
return (ulong)Marshal.ReadIntPtr(threadInformation);
}
finally
{
Marshal.FreeHGlobal(threadInformation);
}
}
finally
{
NativeMethods.CloseHandle(threadHandle);
}
}
#endregion
internal static void SuspendThread(int threadId)
{
var hThread = OpenThread(threadId, NativeMethods.ThreadAccess.SuspendResume);
try
{
SuspendThread(hThread);
}
finally
{
NativeMethods.CloseHandle(hThread);
}
}
internal static void ResumeThread(int threadId)
{
var hThread = OpenThread(threadId, NativeMethods.ThreadAccess.SuspendResume);
try
{
uint suspendCount;
do
{
suspendCount = ResumeThread(hThread);
} while (suspendCount > 1U);
}
finally
{
NativeMethods.CloseHandle(hThread);
}
}
internal class Snapshot : IDisposable
{
private readonly IntPtr _snapshot;
private readonly ProcessThreadCollection _threads;
internal Snapshot(Process process)
{
_snapshot = CreateModuleSnapshot(process.Id);
_threads = process.Threads;
}
internal int GetLastThreadId(string module, int priority)
{
for (var i = _threads.Count - 1; i >= 0; i--)
{
var thread = _threads[i];
if (thread.BasePriority == priority)
{
if (GetThreadModuleName(_snapshot, thread.Id) == module)
{
return thread.Id;
}
}
}
throw new Exception();
}
public void Dispose()
{
NativeMethods.CloseHandle(_snapshot);
}
}
}
}
using System;
using System.Runtime.InteropServices;
namespace Suspender.Utility
{
partial class Api
{
private static class NativeMethods
{
private const string Kernel32 = "kernel32.dll";
private const string Ntdll = "ntdll.dll";
#region Thread
[Flags]
internal enum ThreadAccess : uint
{
// Terminate = 0x0001U,
SuspendResume = 0x0002U,
// GetContext = 0x0008U,
// SetContext = 0x0010U,
// SetInformation = 0x0020U,
QueryInformation = 0x0040U,
// SetThreadToken = 0x0080U,
// Impersonate = 0x0100U,
// DirectImpersonation = 0x0200U
}
[DllImport(Kernel32, SetLastError = true)]
internal static extern IntPtr OpenThread(
ThreadAccess dwDesiredAccess,
bool bInheritHandle, uint dwThreadId);
[DllImport(Kernel32, SetLastError = true)]
internal static extern uint SuspendThread(IntPtr hThread);
[DllImport(Kernel32, SetLastError = true)]
internal static extern uint ResumeThread(IntPtr hThread);
#endregion
#region Snapshot
[Flags]
internal enum Th32Cs : uint
{
// SnapHeapList = 0x00000001U,
// SnapProcess = 0x00000002U,
// SnapThread = 0x00000004U,
SnapModule = 0x00000008U,
SnapModule32 = 0x00000010U,
// SnapAll = (SnapHeapList | SnapProcess | SnapThread | SnapModule),
// NoHeaps = 0x40000000U,
// Inherit = 0x80000000U
}
[DllImport(Kernel32, SetLastError = true)]
internal static extern IntPtr CreateToolhelp32Snapshot(Th32Cs dwFlags, uint th32ProcessId);
#endregion
#region Module
private const int MaxModuleName32 = 255;
private const int MaxPath = 260;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal struct ModuleEntry32
{
internal uint dwSize;
private readonly uint th32ModuleID;
private readonly uint th32ProcessID;
private readonly uint GlblcntUsage;
private readonly uint ProccntUsage;
internal readonly IntPtr modBaseAddr;
internal readonly uint modBaseSize;
private readonly IntPtr hModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxModuleName32 + 1)]
internal readonly string szModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxPath)]
private readonly string szExePath;
}
[DllImport(Kernel32)]
internal static extern bool Module32First(IntPtr hSnapshot, ref ModuleEntry32 lpme);
[DllImport(Kernel32)]
internal static extern bool Module32Next(IntPtr hSnapshot, ref ModuleEntry32 lpme);
#endregion
#region ThreadInformation
internal enum ThreadInfoClass : uint
{
ThreadQuerySetWin32StartAddress = 9U
}
[DllImport(Ntdll)]
internal static extern uint NtQueryInformationThread(IntPtr threadHandle,
ThreadInfoClass threadInformationClass,
IntPtr threadInformation, uint threadInformationLength, IntPtr returnLengthPtr);
#endregion
[DllImport(Kernel32)]
internal static extern bool CloseHandle(IntPtr hObject);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment