// Sanitized server-side AVEVA Historian ValCl context probe. // Logs pointers, GUID bytes, token lengths, round flags, and return values only. 'use strict'; const moduleName = 'aahClientAccessPoint.exe'; const imageBase = ptr('0x00400000'); const moduleBase = Module.findBaseAddress(moduleName); function emit(event) { event.timestampUtc = new Date().toISOString(); console.log(JSON.stringify(event)); } function addrFromVa(va) { if (moduleBase === null) { return null; } return moduleBase.add(ptr(va).sub(imageBase)); } function safePtr(value) { if (value === null || value === undefined) { return null; } try { return ptr(value).toString(); } catch (_) { return null; } } function readU8(pointer) { try { if (pointer.isNull()) return null; return pointer.readU8(); } catch (_) { return null; } } function readU32(pointer) { try { if (pointer.isNull()) return null; return pointer.readU32(); } catch (_) { return null; } } function readGuid(pointer) { try { if (pointer.isNull()) return null; const bytes = pointer.readByteArray(16); if (bytes === null) return null; return Array.prototype.map.call(new Uint8Array(bytes), b => ('0' + b.toString(16)).slice(-2)).join(''); } catch (_) { return null; } } function readServerBufferSummary(buffer) { try { if (buffer.isNull()) { return { buffer: safePtr(buffer) }; } const data = buffer.add(0x48).readPointer(); const length = buffer.add(0x4c).readU32(); let roundByte = null; let wrappedTokenLength = null; if (!data.isNull() && length >= 5) { roundByte = readU8(data); wrappedTokenLength = readU32(data.add(1)); } return { buffer: safePtr(buffer), data: safePtr(data), length: length, roundByte: roundByte, wrappedTokenLength: wrappedTokenLength }; } catch (error) { return { buffer: safePtr(buffer), readError: String(error) }; } } function hook(name, va, callbacks) { const address = addrFromVa(va); if (address === null) { emit({ event: 'hook.error', name: name, reason: 'module-not-loaded', module: moduleName }); return; } try { Interceptor.attach(address, callbacks); emit({ event: 'hook.installed', name: name, va: va, address: address.toString() }); } catch (error) { emit({ event: 'hook.error', name: name, va: va, address: address.toString(), reason: String(error) }); } } emit({ event: 'script.loaded', module: moduleName, moduleBase: moduleBase === null ? null : moduleBase.toString() }); hook('CServerNode.ProcessServerToken', '0x00526E00', { onEnter(args) { this.thisPtr = this.context.ecx; this.contextGuid = args[0]; this.serverBuffer = args[1]; this.continuePtr = args[2]; this.errorPtr = args[3]; emit({ event: 'ProcessServerToken.enter', thisPtr: safePtr(this.thisPtr), contextGuidPtr: safePtr(this.contextGuid), contextGuidBytes: readGuid(this.contextGuid), serverBuffer: readServerBufferSummary(this.serverBuffer), continuePtr: safePtr(this.continuePtr), errorPtr: safePtr(this.errorPtr) }); }, onLeave(retval) { emit({ event: 'ProcessServerToken.leave', retval: retval.toInt32(), continueValue: readU8(this.continuePtr) }); } }); hook('ContextSetup.0050FFC0', '0x0050FFC0', { onEnter(args) { this.thisPtr = this.context.ecx; this.contextGuid = args[0]; emit({ event: 'ContextSetup.enter', thisPtr: safePtr(this.thisPtr), contextGuidPtr: safePtr(this.contextGuid), contextGuidBytes: readGuid(this.contextGuid) }); }, onLeave(retval) { emit({ event: 'ContextSetup.leave', retval: retval.toInt32() }); } }); hook('ContextLookup.00517AB0', '0x00517AB0', { onEnter(args) { this.thisPtr = this.context.ecx; this.outPair = args[0]; this.contextGuid = args[1]; emit({ event: 'ContextLookup.enter', thisPtr: safePtr(this.thisPtr), outPair: safePtr(this.outPair), contextGuidPtr: safePtr(this.contextGuid), contextGuidBytes: readGuid(this.contextGuid) }); }, onLeave(retval) { let first = null; let second = null; try { if (!this.outPair.isNull()) { first = this.outPair.readPointer(); second = this.outPair.add(Process.pointerSize).readPointer(); } } catch (_) { first = null; second = null; } emit({ event: 'ContextLookup.leave', retval: safePtr(retval), contextObject: safePtr(first), contextSharedState: safePtr(second) }); } }); hook('AcquireCredentialsHelper.00505AE0', '0x00505AE0', { onEnter(args) { this.thisPtr = this.context.ecx; this.errorPtr = args[0]; emit({ event: 'AcquireCredentialsHelper.enter', contextObject: safePtr(this.thisPtr), errorPtr: safePtr(this.errorPtr) }); }, onLeave(retval) { emit({ event: 'AcquireCredentialsHelper.leave', retval: retval.toInt32() }); } }); hook('AcceptSecurityContextHelper.00505C00', '0x00505C00', { onEnter(args) { this.thisPtr = this.context.ecx; this.firstRound = args[0].toInt32() & 0xff; this.tokenLength = args[1].toUInt32(); this.tokenPtr = args[2]; this.continuePtr = args[3]; this.serverCredentialPtr = args[4]; this.errorPtr = args[5]; emit({ event: 'AcceptSecurityContextHelper.enter', contextObject: safePtr(this.thisPtr), firstRound: this.firstRound, tokenLength: this.tokenLength, tokenPtr: safePtr(this.tokenPtr), continuePtr: safePtr(this.continuePtr), serverCredentialPtr: safePtr(this.serverCredentialPtr), errorPtr: safePtr(this.errorPtr) }); }, onLeave(retval) { emit({ event: 'AcceptSecurityContextHelper.leave', retval: retval.toInt32(), continueValue: readU8(this.continuePtr) }); } });