Files
2026-08-03 18:31:59 +03:00

105 lines
4.5 KiB
PowerShell

#requires -Version 5.1
<#
Build adsource.dll forwarder proxy.
Parses pragmas.txt, generates _forwarders.c with #pragma comment(linker, "/export:...")
directives that create real PE forwarder entries pointing to adsource_original.dll.
No .def file — pragmas handle all 147 exports reliably (including mangled C++ names).
DllMain payload fires on load; every real export is served by the genuine DLL.
#>
[CmdletBinding()]
param(
[string]$PragmasFile = (Join-Path $PSScriptRoot 'pragmas.txt'),
[string]$Source = (Join-Path $PSScriptRoot 'adsource_proxy.cpp'),
[string]$OutputDll = (Join-Path $PSScriptRoot 'adsource.dll')
)
$ErrorActionPreference = 'Stop'
# --- Locate MSVC toolchain --------------------------------------------------
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (-not (Test-Path $vswhere)) { $vswhere = "${env:ProgramFiles}\Microsoft Visual Studio\Installer\vswhere.exe" }
if (-not (Test-Path $vswhere)) { throw "vswhere not found." }
$vsPath = & $vswhere -latest -property installationPath
$vcvars = Join-Path $vsPath 'VC\Auxiliary\Build\vcvars64.bat'
if (-not (Test-Path $vcvars)) { throw "vcvars64.bat not found at $vcvars" }
Write-Host "[+] Toolchain: $vsPath"
# --- Parse pragmas ----------------------------------------------------------
Write-Host "[+] Parsing $PragmasFile"
$entries = New-Object System.Collections.Generic.List[PSObject]
Get-Content $PragmasFile | ForEach-Object {
if ($_ -match '/export:([^=]+)=adsource\.[^,]+,@(\d+)') {
$entries.Add([PSCustomObject]@{ Name = $matches[1]; Ordinal = [int]$matches[2] })
}
}
if ($entries.Count -eq 0) { throw "No exports parsed from $PragmasFile" }
Write-Host "[+] Parsed $($entries.Count) exports"
# --- Generate _forwarders.c with pragma-based PE forwarders ------------------
$fwdSrc = Join-Path $PSScriptRoot '_forwarders.c'
$sb = [System.Text.StringBuilder]::new()
[void]$sb.AppendLine('// Auto-generated PE forwarder exports -> adsource_original.dll')
foreach ($e in $entries) {
[void]$sb.AppendLine("#pragma comment(linker, `"/export:$($e.Name)=adsource_original.$($e.Name),@$($e.Ordinal)`")")
}
[IO.File]::WriteAllText($fwdSrc, $sb.ToString(), [Text.Encoding]::ASCII)
Write-Host "[+] Wrote $fwdSrc ($($entries.Count) forwarder pragmas)"
# --- Compile + link via vcvars64 --------------------------------------------
Write-Host "[+] Compiling..."
$mainObj = $Source -replace '\.cpp$', '.obj'
$fwdObj = $fwdSrc -replace '\.c$', '.obj'
$buildCmd = @"
call "$vcvars" >nul 2>&1
cl /nologo /W3 /O1 /MT /GS- /Zl /c /Fo"$mainObj" "$Source"
if errorlevel 1 exit /b 1
cl /nologo /W3 /O1 /c /Fo"$fwdObj" "$fwdSrc"
if errorlevel 1 exit /b 1
link /nologo /DLL /MACHINE:X64 /SUBSYSTEM:WINDOWS /ENTRY:DllMain /OUT:"$OutputDll" "$mainObj" "$fwdObj" kernel32.lib user32.lib advapi32.lib
"@
$tmpBat = Join-Path $PSScriptRoot '_build.bat'
$buildCmd | Out-File $tmpBat -Encoding ascii
$buildOut = cmd /c $tmpBat 2>&1
$buildExit = $LASTEXITCODE
Remove-Item $tmpBat -Force
$buildOut | ForEach-Object { Write-Host " $_" }
if ($buildExit -ne 0 -or -not (Test-Path $OutputDll)) {
throw "Build failed (exit $buildExit)."
}
$fi = Get-Item $OutputDll
Write-Host "[+] Built: $OutputDll ($($fi.Length) bytes)" -ForegroundColor Green
# --- Verify forwarder exports -----------------------------------------------
Write-Host "[+] Verifying exports (expecting PE forwarders)..."
$dumpFile = Join-Path $PSScriptRoot '_dumpbin.txt'
& cmd /c "call `"$vcvars`" >nul 2>&1 && dumpbin /nologo /EXPORTS `"$OutputDll`"" |
Out-File $dumpFile -Encoding ascii
$dumpLines = Get-Content $dumpFile
Remove-Item $dumpFile -Force
$forwarderCount = @($dumpLines | Where-Object { $_ -match '\(forwarded to adsource_original\.' }).Count
$stubCount = @($dumpLines | Where-Object { $_ -match 'Stub' }).Count
Write-Host "[+] Forwarder exports: $forwarderCount / $($entries.Count)" -ForegroundColor $(if ($forwarderCount -ge $entries.Count) { 'Green' } else { 'Yellow' })
if ($stubCount -gt 0) {
Write-Warning "Found $stubCount Stub references in export table (should be 0 for forwarder build)"
}
if ($forwarderCount -lt $entries.Count) {
Write-Warning "Missing $(($entries.Count - $forwarderCount)) forwarders -- check dumpbin output"
}
# --- Cleanup temp files -----------------------------------------------------
Remove-Item $fwdSrc -Force -ErrorAction SilentlyContinue
Remove-Item $fwdObj -Force -ErrorAction SilentlyContinue
Remove-Item $mainObj -Force -ErrorAction SilentlyContinue
Write-Host ""
Write-Host "Output: $OutputDll" -ForegroundColor Green