/// <summary> /// Adds the specified module to the MBBS Host /// /// This includes: /// - Patching Relocation Information for Exported Modules /// - Setting up Module Memory and loading Disassembly /// - Executing Module "_INIT_" routine /// </summary> /// <param name="module"></param> public void AddModule(MbbsModule module) { if (_isRunning) { throw new Exception("Unable to Add Module after host is running"); } _logger.Info($"Adding Module {module.ModuleIdentifier}..."); //Patch Relocation Information to Bytecode PatchRelocation(module); //Run Segments through AOT Decompiler & add them to Memory foreach (var seg in module.File.SegmentTable) { module.Memory.AddSegment(seg); _logger.Info($"Segment {seg.Ordinal} ({seg.Data.Length} bytes) loaded!"); } //Setup Exported Modules module.ExportedModuleDictionary.Add(Majorbbs.Segment, GetFunctions(module, "MAJORBBS")); module.ExportedModuleDictionary.Add(Galgsbl.Segment, GetFunctions(module, "GALGSBL")); module.ExportedModuleDictionary.Add(Phapi.Segment, GetFunctions(module, "PHAPI")); module.ExportedModuleDictionary.Add(Galme.Segment, GetFunctions(module, "GALME")); module.ExportedModuleDictionary.Add(Doscalls.Segment, GetFunctions(module, "DOSCALLS")); //Add it to the Module Dictionary _modules[module.ModuleIdentifier] = module; module.StateCode = (short)(_modules.Count + 1); //Run INIT Run(module.ModuleIdentifier, module.EntryPoints["_INIT_"], ushort.MaxValue); _logger.Info($"Module {module.ModuleIdentifier} added!"); }
protected ExportedModuleTestBase(string modulePath) { mbbsEmuMemoryCore = new MemoryCore(); mbbsEmuCpuRegisters = new CpuRegisters(); mbbsEmuCpuCore = new CpuCore(); mbbsModule = new MbbsModule(FileUtility.CreateForTest(), _serviceResolver.GetService <ILogger>(), null, modulePath, mbbsEmuMemoryCore); testSessions = new PointerDictionary <SessionBase>(); testSessions.Allocate(new TestSession(null)); testSessions.Allocate(new TestSession(null)); majorbbs = new HostProcess.ExportedModules.Majorbbs( _serviceResolver.GetService <ILogger>(), _serviceResolver.GetService <AppSettings>(), _serviceResolver.GetService <IFileUtility>(), _serviceResolver.GetService <IGlobalCache>(), mbbsModule, testSessions, _serviceResolver.GetService <IAccountKeyRepository>(), _serviceResolver.GetService <IAccountRepository>()); galgsbl = new HostProcess.ExportedModules.Galgsbl( _serviceResolver.GetService <ILogger>(), _serviceResolver.GetService <AppSettings>(), _serviceResolver.GetService <IFileUtility>(), _serviceResolver.GetService <IGlobalCache>(), mbbsModule, testSessions); mbbsEmuCpuCore.Reset(mbbsEmuMemoryCore, mbbsEmuCpuRegisters, ExportedFunctionDelegate); }
public Galgsbl(MbbsModule module, PointerDictionary <SessionBase> channelDictionary) : base(module, channelDictionary) { _startDate = DateTime.Now; Module.Memory.AllocateVariable("BTURNO", 9); //Check for Module Specific Activation # var bturno = _configuration["GSBL.Activation"]; if (!string.IsNullOrEmpty(_configuration[$"GSBL.Activation.{Module.ModuleIdentifier}"])) { bturno = _configuration[$"GSBL.Activation.{Module.ModuleIdentifier}"]; _logger.Info($"Found Module Specific Activation # for {Module.ModuleIdentifier}. Setting BTURNO to: {bturno}"); } //Sanity Check if (bturno.Length > 8) { bturno = bturno.Substring(0, 8); } Module.Memory.SetArray("BTURNO", Encoding.ASCII.GetBytes($"{bturno}\0")); Module.Memory.AllocateVariable("TICKER", 0x02); //ushort increments once per second MonitoredChannel2 = 0xFFFF; MonitoredChannel = 0xFFFF; new Thread(Timer1Hz).Start(); }
internal Galme(MbbsModule module, PointerDictionary <SessionBase> channelDictionary) : base(module, channelDictionary) { var txtlenPointer = Module.Memory.AllocateVariable("TXTLEN", 0x2); Module.Memory.SetWord(txtlenPointer, 0x400); }
protected MajorbbsTestBase() { mbbsEmuMemoryCore = new MemoryCore(); mbbsEmuCpuRegisters = new CpuRegisters(); mbbsEmuCpuCore = new CpuCore(); mbbsModule = new MbbsModule(FileUtility.CreateForTest(), null, string.Empty, mbbsEmuMemoryCore); majorbbs = new HostProcess.ExportedModules.Majorbbs(mbbsModule, new PointerDictionary <Session.SessionBase>()); mbbsEmuCpuCore.Reset(mbbsEmuMemoryCore, mbbsEmuCpuRegisters, MajorbbsFunctionDelegate); }
private protected ExportedModuleBase(ILogger logger, AppSettings configuration, IFileUtility fileUtility, IGlobalCache globalCache, MbbsModule module, PointerDictionary <SessionBase> channelDictionary) { _logger = logger; _configuration = configuration; _fileFinder = fileUtility; _globalCache = globalCache; Module = module; ChannelDictionary = channelDictionary; FilePointerDictionary = new PointerDictionary <FileStream>(1, int.MaxValue); McvPointerDictionary = new PointerDictionary <McvFile>(); }
private protected static readonly byte[] NEW_LINE = { (byte)'\r', (byte)'\n' }; //Just easier to read private protected ExportedModuleBase(MbbsModule module, PointerDictionary <SessionBase> channelDictionary) { _logger = ServiceResolver.GetService <ILogger>(); _configuration = ServiceResolver.GetService <IConfiguration>(); _fileFinder = ServiceResolver.GetService <IFileUtility>(); _globalCache = ServiceResolver.GetService <IGlobalCache>(); Module = module; ChannelDictionary = channelDictionary; FilePointerDictionary = new PointerDictionary <FileStream>(1, int.MaxValue); McvPointerDictionary = new PointerDictionary <McvFile>(); BtrievePointerDictionaryNew = new Dictionary <IntPtr16, BtrieveFileProcessor>(); }
protected MajorbbsTestBase() { mbbsEmuMemoryCore = new MemoryCore(); mbbsEmuCpuRegisters = new CpuRegisters(); mbbsEmuCpuCore = new CpuCore(); mbbsModule = new MbbsModule(FileUtility.CreateForTest(), _serviceResolver.GetService <ILogger>(), null, string.Empty, mbbsEmuMemoryCore); majorbbs = new HostProcess.ExportedModules.Majorbbs( _serviceResolver.GetService <ILogger>(), _serviceResolver.GetService <IConfiguration>(), _serviceResolver.GetService <IFileUtility>(), _serviceResolver.GetService <IGlobalCache>(), mbbsModule, new PointerDictionary <Session.SessionBase>()); mbbsEmuCpuCore.Reset(mbbsEmuMemoryCore, mbbsEmuCpuRegisters, MajorbbsFunctionDelegate); }
protected ExportedModuleTestBase(string modulePath) { _serviceResolver = new ServiceResolver(fakeClock, SessionBuilder.ForTest($"MBBSDb_{RANDOM.Next()}")); var textVariableService = _serviceResolver.GetService <ITextVariableService>(); mbbsEmuMemoryCore = mbbsEmuProtectedModeMemoryCore = new ProtectedModeMemoryCore(_serviceResolver.GetService <ILogger>()); mbbsEmuCpuCore = new CpuCore(_serviceResolver.GetService <ILogger>()); mbbsEmuCpuRegisters = mbbsEmuCpuCore; var testModuleConfig = new ModuleConfiguration { ModulePath = modulePath, ModuleEnabled = true }; mbbsModule = new MbbsModule(FileUtility.CreateForTest(), fakeClock, _serviceResolver.GetService <ILogger>(), testModuleConfig, mbbsEmuProtectedModeMemoryCore); testSessions = new PointerDictionary <SessionBase>(); testSessions.Allocate(new TestSession(null, textVariableService)); testSessions.Allocate(new TestSession(null, textVariableService)); majorbbs = new HostProcess.ExportedModules.Majorbbs( _serviceResolver.GetService <IClock>(), _serviceResolver.GetService <ILogger>(), _serviceResolver.GetService <AppSettings>(), _serviceResolver.GetService <IFileUtility>(), _serviceResolver.GetService <IGlobalCache>(), mbbsModule, testSessions, _serviceResolver.GetService <IAccountKeyRepository>(), _serviceResolver.GetService <IAccountRepository>(), textVariableService); galgsbl = new HostProcess.ExportedModules.Galgsbl( _serviceResolver.GetService <IClock>(), _serviceResolver.GetService <ILogger>(), _serviceResolver.GetService <AppSettings>(), _serviceResolver.GetService <IFileUtility>(), _serviceResolver.GetService <IGlobalCache>(), mbbsModule, testSessions, textVariableService); mbbsEmuCpuCore.Reset( mbbsEmuMemoryCore, (ordinal, functionOrdinal) => ExportedFunctionDelegate(ordinal, functionOrdinal, offsetsOnly: false), null, null); }
/// <summary> /// Returns the specified Exported Module for the specified MajorBBS Module /// /// Each Module gets its own copy of the Exported Modules, this module keeps track /// of them using a Dictionary and will create them as needed. /// </summary> /// <param name="module"></param> /// <param name="exportedModule"></param> /// <returns></returns> private IExportedModule GetFunctions(MbbsModule module, string exportedModule) { var key = $"{module.ModuleIdentifier}-{exportedModule}"; if (!_exportedFunctions.TryGetValue(key, out var functions)) { _exportedFunctions[key] = exportedModule switch { "MAJORBBS" => new Majorbbs(Logger, _configuration, _fileUtility, _globalCache, module, _channelDictionary, _accountKeyRepository, _accountRepository), "GALGSBL" => new Galgsbl(Logger, _configuration, _fileUtility, _globalCache, module, _channelDictionary), "DOSCALLS" => new Doscalls(Logger, _configuration, _fileUtility, _globalCache, module, _channelDictionary), "GALME" => new Galme(Logger, _configuration, _fileUtility, _globalCache, module, _channelDictionary), "PHAPI" => new Phapi(Logger, _configuration, _fileUtility, _globalCache, module, _channelDictionary), "GALMSG" => new Galmsg(Logger, _configuration, _fileUtility, _globalCache, module, _channelDictionary), _ => throw new Exception($"Unknown Exported Library: {exportedModule}") }; functions = _exportedFunctions[key]; } return(functions); }
/// <summary> /// Returns the specified Exported Module for the specified MajorBBS Module /// /// Each Module gets its own copy of the Exported Modules, this module keeps track /// of them using a Dictionary and will create them as needed. /// </summary> /// <param name="module"></param> /// <param name="exportedModule"></param> /// <returns></returns> private IExportedModule GetFunctions(MbbsModule module, string exportedModule) { var key = $"{module.ModuleIdentifier}-{exportedModule}"; if (!_exportedFunctions.TryGetValue(key, out var functions)) { _exportedFunctions[key] = exportedModule switch { "MAJORBBS" => new Majorbbs(module, _channelDictionary), "GALGSBL" => new Galgsbl(module, _channelDictionary), "DOSCALLS" => new Doscalls(module, _channelDictionary), "GALME" => new Galme(module, _channelDictionary), "PHAPI" => new Phapi(module, _channelDictionary), "GALMSG" => new Galmsg(module, _channelDictionary), _ => throw new Exception($"Unknown Exported Library: {exportedModule}") }; functions = _exportedFunctions[key]; } return(functions); }
protected ExportedModuleTestBase(string modulePath) { _serviceResolver = new ServiceResolver(fakeClock, SessionBuilder.ForTest($"MBBSDb_{RANDOM.Next()}")); var textVariableService = _serviceResolver.GetService <ITextVariableService>(); mbbsEmuMemoryCore = new MemoryCore(); mbbsEmuCpuRegisters = new CpuRegisters(); mbbsEmuCpuCore = new CpuCore(); mbbsModule = new MbbsModule(FileUtility.CreateForTest(), fakeClock, _serviceResolver.GetService <ILogger>(), null, modulePath, mbbsEmuMemoryCore); testSessions = new PointerDictionary <SessionBase>(); testSessions.Allocate(new TestSession(null, textVariableService)); testSessions.Allocate(new TestSession(null, textVariableService)); majorbbs = new HostProcess.ExportedModules.Majorbbs( _serviceResolver.GetService <IClock>(), _serviceResolver.GetService <ILogger>(), _serviceResolver.GetService <AppSettings>(), _serviceResolver.GetService <IFileUtility>(), _serviceResolver.GetService <IGlobalCache>(), mbbsModule, testSessions, _serviceResolver.GetService <IAccountKeyRepository>(), _serviceResolver.GetService <IAccountRepository>()); galgsbl = new HostProcess.ExportedModules.Galgsbl( _serviceResolver.GetService <IClock>(), _serviceResolver.GetService <ILogger>(), _serviceResolver.GetService <AppSettings>(), _serviceResolver.GetService <IFileUtility>(), _serviceResolver.GetService <IGlobalCache>(), mbbsModule, testSessions); mbbsEmuCpuCore.Reset(mbbsEmuMemoryCore, mbbsEmuCpuRegisters, ExportedFunctionDelegate, null); }
internal Phapi(IClock clock, ILogger logger, AppSettings configuration, IFileUtility fileUtility, IGlobalCache globalCache, MbbsModule module, PointerDictionary <SessionBase> channelDictionary) : base( clock, logger, configuration, fileUtility, globalCache, module, channelDictionary) { }
internal Phapi(MbbsModule module, PointerDictionary <SessionBase> channelDictionary) : base(module, channelDictionary) { }
internal Galme(IClock clock, ILogger logger, AppSettings configuration, IFileUtility fileUtility, IGlobalCache globalCache, MbbsModule module, PointerDictionary <SessionBase> channelDictionary, ITextVariableService textVariableService) : base( clock, logger, configuration, fileUtility, globalCache, module, channelDictionary, textVariableService) { var txtlenPointer = Module.Memory.AllocateVariable("TXTLEN", 0x2); Module.Memory.SetWord(txtlenPointer, 0x400); }
internal Galme(ILogger logger, IConfiguration configuration, IFileUtility fileUtility, IGlobalCache globalCache, MbbsModule module, PointerDictionary <SessionBase> channelDictionary) : base( logger, configuration, fileUtility, globalCache, module, channelDictionary) { var txtlenPointer = Module.Memory.AllocateVariable("TXTLEN", 0x2); Module.Memory.SetWord(txtlenPointer, 0x400); }
public Galgsbl(IClock clock, ILogger logger, AppSettings configuration, IFileUtility fileUtility, IGlobalCache globalCache, MbbsModule module, PointerDictionary <SessionBase> channelDictionary) : base( clock, logger, configuration, fileUtility, globalCache, module, channelDictionary) { _startDate = clock.Now; Module.Memory.AllocateVariable("BTURNO", 9); //Check for Module Specific BTURNO # var bturno = configuration.GSBLBTURNO; if (!string.IsNullOrEmpty(_configuration.GetBTURNO(Module.ModuleIdentifier))) { bturno = _configuration.GetBTURNO(Module.ModuleIdentifier); _logger.Info($"{Module.ModuleIdentifier} Found Module Specific BTURNO # -- Setting BTURNO to: {bturno}"); } //Sanity Check if (bturno.Length > 8) { bturno = bturno.Substring(0, 8); } Module.Memory.SetArray("BTURNO", Encoding.ASCII.GetBytes($"{bturno}\0")); Module.Memory.AllocateVariable("TICKER", 0x02); //ushort increments once per second MonitoredChannel2 = 0xFFFF; MonitoredChannel = 0xFFFF; TimeSpan timeSpan = TimeSpan.FromSeconds(1); _timer = new Timer(OnTimerCallback, this, timeSpan, timeSpan); }
internal Doscalls(ILogger logger, AppSettings configuration, IFileUtility fileUtility, IGlobalCache globalCache, MbbsModule module, PointerDictionary <SessionBase> channelDictionary) : base( logger, configuration, fileUtility, globalCache, module, channelDictionary) { }
public ApiReport(MbbsModule module) { _module = module; _logger = ServiceResolver.GetService <ILogger>(); }
internal Doscalls(IClock clock, ILogger logger, AppSettings configuration, IFileUtility fileUtility, IGlobalCache globalCache, MbbsModule module, PointerDictionary <SessionBase> channelDictionary, ITextVariableService textVariableService) : base( clock, logger, configuration, fileUtility, globalCache, module, channelDictionary, textVariableService) { }
/// <summary> /// Patches Relocation information from each Code Segment Relocation Records into the Segment Byte Code /// /// Because the compiler doesn't know the location in memory of the hosts Exported Modules (Imported when /// viewed from the standpoint of the DLL), it saves the information to the Relocation Records for the /// given Code Segment. /// /// The x86 Emulator knows that any CALL FAR to a Segment >= 0xFF00 is an emulated Exported Module and properly /// handles calling the correct Module using the Segment of the target, and the Ordinal of the call using the Offset. /// A relocation record for a call to MAJORBBS->ATOL() would be patched as: /// /// CALL FAR 0xFFFF:0x004D /// /// Segment & Offset meaning: /// 0xFFFF == MAJORBBS /// 0x004D == 77, Ordinal for ATOL() /// </summary> /// <param name="module"></param> private void PatchRelocation(MbbsModule module) { //Declare Host Functions var majorbbsHostFunctions = GetFunctions(module, "MAJORBBS"); var galsblHostFunctions = GetFunctions(module, "GALGSBL"); var doscallsHostFunctions = GetFunctions(module, "DOSCALLS"); var galmeFunctions = GetFunctions(module, "GALME"); var phapiFunctions = GetFunctions(module, "PHAPI"); var galmsgFunctions = GetFunctions(module, "GALMSG"); foreach (var s in module.File.SegmentTable) { if (s.RelocationRecords == null || s.RelocationRecords.Count == 0) { continue; } foreach (var relocationRecord in s.RelocationRecords.Values) { //Ignored Relocation Record if (relocationRecord.TargetTypeValueTuple == null) { continue; } switch (relocationRecord.TargetTypeValueTuple.Item1) { case EnumRecordsFlag.ImportOrdinalAdditive: case EnumRecordsFlag.ImportOrdinal: { var nametableOrdinal = relocationRecord.TargetTypeValueTuple.Item2; var functionOrdinal = relocationRecord.TargetTypeValueTuple.Item3; var relocationResult = module.File.ImportedNameTable[nametableOrdinal].Name switch { "MAJORBBS" => majorbbsHostFunctions.Invoke(functionOrdinal, true), "GALGSBL" => galsblHostFunctions.Invoke(functionOrdinal, true), "DOSCALLS" => doscallsHostFunctions.Invoke(functionOrdinal, true), "GALME" => galmeFunctions.Invoke(functionOrdinal, true), "PHAPI" => phapiFunctions.Invoke(functionOrdinal, true), "GALMSG" => galmsgFunctions.Invoke(functionOrdinal, true), _ => throw new Exception( $"Unknown or Unimplemented Imported Library: {module.File.ImportedNameTable[nametableOrdinal].Name}") }; var relocationPointer = new IntPtr16(relocationResult); //32-Bit Pointer if (relocationRecord.SourceType == 3) { Array.Copy(relocationPointer.ToArray(), 0, s.Data, relocationRecord.Offset, 4); continue; } //16-Bit Values var result = relocationRecord.SourceType switch { //Offset 2 => relocationPointer.Segment, 5 => relocationPointer.Offset, _ => throw new ArgumentOutOfRangeException( $"Unhandled Relocation Source Type: {relocationRecord.SourceType}") }; if (relocationRecord.Flag.HasFlag(EnumRecordsFlag.ImportOrdinalAdditive)) { result += BitConverter.ToUInt16(s.Data, relocationRecord.Offset); } Array.Copy(BitConverter.GetBytes(result), 0, s.Data, relocationRecord.Offset, 2); break; } case EnumRecordsFlag.InternalRef: { //32-Bit Pointer if (relocationRecord.SourceType == 3) { var relocationPointer = new IntPtr16(relocationRecord.TargetTypeValueTuple.Item2, relocationRecord.TargetTypeValueTuple.Item4); Array.Copy(relocationPointer.ToArray(), 0, s.Data, relocationRecord.Offset, 4); break; } Array.Copy(BitConverter.GetBytes(relocationRecord.TargetTypeValueTuple.Item2), 0, s.Data, relocationRecord.Offset, 2); break; } case EnumRecordsFlag.ImportNameAdditive: case EnumRecordsFlag.ImportName: { var nametableOrdinal = relocationRecord.TargetTypeValueTuple.Item2; var functionOrdinal = relocationRecord.TargetTypeValueTuple.Item3; var newSegment = module.File.ImportedNameTable[nametableOrdinal].Name switch { "MAJORBBS" => Majorbbs.Segment, "GALGSBL" => Galgsbl.Segment, "PHAPI" => Phapi.Segment, "GALME" => Galme.Segment, "DOSCALLS" => Doscalls.Segment, _ => throw new Exception( $"Unknown or Unimplemented Imported Module: {module.File.ImportedNameTable[nametableOrdinal].Name}") }; var relocationPointer = new IntPtr16(newSegment, functionOrdinal); //32-Bit Pointer if (relocationRecord.SourceType == 3) { Array.Copy(relocationPointer.ToArray(), 0, s.Data, relocationRecord.Offset, 4); continue; } //16-Bit Values var result = relocationRecord.SourceType switch { //Offset 2 => relocationPointer.Segment, 5 => relocationPointer.Offset, _ => throw new ArgumentOutOfRangeException( $"Unhandled Relocation Source Type: {relocationRecord.SourceType}") }; if (relocationRecord.Flag.HasFlag(EnumRecordsFlag.ImportNameAdditive)) { result += BitConverter.ToUInt16(s.Data, relocationRecord.Offset); } Array.Copy(BitConverter.GetBytes(result), 0, s.Data, relocationRecord.Offset, 2); break; } default: throw new Exception("Unsupported Records Flag for Relocation Value"); } } } }
internal Doscalls(MbbsModule module, PointerDictionary <SessionBase> channelDictionary) : base(module, channelDictionary) { }
public ApiReport(ILogger logger, MbbsModule module) { _module = module; _logger = logger; }
internal Galmsg(ILogger logger, IConfiguration configuration, IFileUtility fileUtility, IGlobalCache globalCache, MbbsModule module, PointerDictionary <SessionBase> channelDictionary) : base( logger, configuration, fileUtility, globalCache, module, channelDictionary) { }