Skip to content

Instantly share code, notes, and snippets.

@Seeker14491
Created May 8, 2021 22:32
Show Gist options
  • Save Seeker14491/f714985cb594adf99f7a99c509ad0971 to your computer and use it in GitHub Desktop.
Save Seeker14491/f714985cb594adf99f7a99c509ad0971 to your computer and use it in GitHub Desktop.
using System;
using System.IO;
using System.Security.Cryptography;
using System.Threading;
using SteamKit2;
namespace SteamKit2Exploration
{
class Program
{
static SteamClient steamClient;
static CallbackManager manager;
static SteamUser steamUser;
static SteamUserStats steamUserStats;
static bool isRunning;
static string user, pass;
static string authCode, twoFactorAuth;
static void Main( string[] args )
{
if ( args.Length < 2 )
{
Console.WriteLine( "No username and password specified!" );
return;
}
// save our logon details
user = args[ 0 ];
pass = args[ 1 ];
// create our steamclient instance
steamClient = new SteamClient();
// create the callback manager which will route callbacks to function calls
manager = new CallbackManager( steamClient );
// get the steamuser handler, which is used for logging on after successfully connecting
steamUser = steamClient.GetHandler<SteamUser>();
steamUserStats = steamClient.GetHandler<SteamUserStats>();
// register a few callbacks we're interested in
// these are registered upon creation to a callback manager, which will then route the callbacks
// to the functions specified
manager.Subscribe<SteamClient.ConnectedCallback>( OnConnected );
manager.Subscribe<SteamClient.DisconnectedCallback>( OnDisconnected );
manager.Subscribe<SteamUser.LoggedOnCallback>( OnLoggedOn );
manager.Subscribe<SteamUser.LoggedOffCallback>( OnLoggedOff );
// this callback is triggered when the steam servers wish for the client to store the sentry file
manager.Subscribe<SteamUser.UpdateMachineAuthCallback>( OnMachineAuth );
manager.Subscribe<SteamUserStats.FindOrCreateLeaderboardCallback>(OnFindOrCreateLeaderboard);
isRunning = true;
Console.WriteLine( "Connecting to Steam..." );
// initiate the connection
steamClient.Connect();
// create our callback handling loop
while ( isRunning )
{
// in order for the callbacks to get routed, they need to be handled by the manager
manager.RunWaitCallbacks( TimeSpan.FromSeconds( 1 ) );
}
}
private static void OnFindOrCreateLeaderboard(SteamUserStats.FindOrCreateLeaderboardCallback callback)
{
if (callback.Result == EResult.OK)
{
Console.WriteLine($"Found leaderboard with {callback.EntryCount} entries.");
}
}
static void OnConnected( SteamClient.ConnectedCallback callback )
{
Console.WriteLine( "Connected to Steam! Logging in '{0}'...", user );
byte[] sentryHash = null;
if ( File.Exists( "sentry.bin" ) )
{
// if we have a saved sentry file, read and sha-1 hash it
byte[] sentryFile = File.ReadAllBytes( "sentry.bin" );
sentryHash = CryptoHelper.SHAHash( sentryFile );
}
steamUser.LogOn( new SteamUser.LogOnDetails
{
Username = user,
Password = pass,
// in this sample, we pass in an additional authcode
// this value will be null (which is the default) for our first logon attempt
AuthCode = authCode,
// if the account is using 2-factor auth, we'll provide the two factor code instead
// this will also be null on our first logon attempt
TwoFactorCode = twoFactorAuth,
// our subsequent logons use the hash of the sentry file as proof of ownership of the file
// this will also be null for our first (no authcode) and second (authcode only) logon attempts
SentryFileHash = sentryHash,
} );
}
static void OnDisconnected( SteamClient.DisconnectedCallback callback )
{
// after recieving an AccountLogonDenied, we'll be disconnected from steam
// so after we read an authcode from the user, we need to reconnect to begin the logon flow again
Console.WriteLine( "Disconnected from Steam, reconnecting in 5..." );
Thread.Sleep( TimeSpan.FromSeconds( 5 ) );
steamClient.Connect();
}
static void OnLoggedOn( SteamUser.LoggedOnCallback callback )
{
bool isSteamGuard = callback.Result == EResult.AccountLogonDenied;
bool is2FA = callback.Result == EResult.AccountLoginDeniedNeedTwoFactor;
if ( isSteamGuard || is2FA )
{
Console.WriteLine( "This account is SteamGuard protected!" );
if ( is2FA )
{
Console.Write( "Please enter your 2 factor auth code from your authenticator app: " );
twoFactorAuth = Console.ReadLine();
}
else
{
Console.Write( "Please enter the auth code sent to the email at {0}: ", callback.EmailDomain );
authCode = Console.ReadLine();
}
return;
}
if ( callback.Result != EResult.OK )
{
Console.WriteLine( "Unable to logon to Steam: {0} / {1}", callback.Result, callback.ExtendedResult );
isRunning = false;
return;
}
Console.WriteLine( "Successfully logged on!" );
var result = steamUserStats.FindLeaderboard(233610, "Inferno_1_Stable").GetAwaiter();
}
static void OnLoggedOff( SteamUser.LoggedOffCallback callback )
{
Console.WriteLine( "Logged off of Steam: {0}", callback.Result );
}
static void OnMachineAuth( SteamUser.UpdateMachineAuthCallback callback )
{
Console.WriteLine( "Updating sentryfile..." );
// write out our sentry file
// ideally we'd want to write to the filename specified in the callback
// but then this sample would require more code to find the correct sentry file to read during logon
// for the sake of simplicity, we'll just use "sentry.bin"
int fileSize;
byte[] sentryHash;
using ( var fs = File.Open( "sentry.bin", FileMode.OpenOrCreate, FileAccess.ReadWrite ) )
{
fs.Seek( callback.Offset, SeekOrigin.Begin );
fs.Write( callback.Data, 0, callback.BytesToWrite );
fileSize = ( int )fs.Length;
fs.Seek( 0, SeekOrigin.Begin );
using ( var sha = SHA1.Create() )
{
sentryHash = sha.ComputeHash( fs );
}
}
// inform the steam servers that we're accepting this sentry file
steamUser.SendMachineAuthResponse( new SteamUser.MachineAuthDetails
{
JobID = callback.JobID,
FileName = callback.FileName,
BytesWritten = callback.BytesToWrite,
FileSize = fileSize,
Offset = callback.Offset,
Result = EResult.OK,
LastError = 0,
OneTimePassword = callback.OneTimePassword,
SentryFileHash = sentryHash,
} );
Console.WriteLine( "Done!" );
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment