@CODYQX4 You can override the Execute event with your own code in a derived class. In there you must use your KMS code to determine what goes back to the client. Code: /// <summary> /// Can be over-ridden in a derived class to handle the incomming RPC request, or you can /// subscribe to the OnExecute event. /// </summary> public virtual byte[] Execute(IRpcClientInfo client, byte[] input) { RpcExecuteHandler proc = _handler; if (proc != null) { return proc(client, input); } return null; } I also found some VB.Net code that can be converted to C# that you can use to communicate over TCP/IP: Code: Public Class Form1 Private listener As System.Net.Sockets.TcpListener Private listenThread As System.Threading.Thread Private clients As New List(Of ConnectedClient) 'This list will store all connected clients. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load listener = New System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 43001) 'The TcpListener will listen for incoming connections at port 43001 listener.Start() 'Start listening. listenThread = New System.Threading.Thread(AddressOf doListen) 'This thread will run the doListen method listenThread.IsBackground = True 'Since we dont want this thread to keep on running after the application closes, we set isBackground to true. listenThread.Start() 'Start executing doListen on the worker thread. End Sub Private Sub doListen() Dim incomingClient As System.Net.Sockets.TcpClient Do incomingClient = listener.AcceptTcpClient 'Accept the incoming connection. This is a blocking method so execution will halt here until someone tries to connect. Dim connClient As New ConnectedClient(incomingClient, Me) 'Create a new instance of ConnectedClient (check its constructor to see whats happening now). AddHandler connClient.dataReceived, AddressOf Me.messageReceived clients.Add(connClient) 'Adds the connected client to the list of connected clients. Loop End Sub Public Sub removeClient(ByVal client As ConnectedClient) If clients.Contains(client) Then clients.Remove(client) End If End Sub Private Sub messageReceived(ByVal sender As ConnectedClient, ByVal message As String) 'A message has been received from one of the clients. 'To determine who its from, use the sender object. 'sender.SendMessage can be used to reply to the sender. Dim data() As String = message.Split("|"c) 'Split the message on each | and place in the string array. Select Case data(0) Case "CONNECT" 'We use GetClientByName to make sure no one else is using this username. 'It will return Nothing if the username is free. 'Since the client sent the message in this format: CONNECT|UserName, the username will be in the array on index 1. If GetClientByName(data(1)) Is Nothing Then 'The username is not taken, we can safely assign it to the sender. sender.Username = data(1) End If Case "DISCONNECT" removeClient(sender) End Select End Sub Private Function GetClientByName(ByVal name As String) As ConnectedClient For Each cc As ConnectedClient In clients If cc.Username = name Then Return cc 'client found, return it. End If Next 'If we've reached this part of the method, there is no client by that name Return Nothing End Function End Class Public Class ConnectedClient Private mClient As System.Net.Sockets.TcpClient Private mUsername As String Private mParentForm As Form1 Private readThread As System.Threading.Thread Private Const MESSAGE_DELIMITER As Char = ControlChars.Cr Public Event dataReceived(ByVal sender As ConnectedClient, ByVal message As String) Sub New(ByVal client As System.Net.Sockets.TcpClient, ByVal parentForm As Form1) mParentForm = parentForm mClient = client readThread = New System.Threading.Thread(AddressOf doRead) readThread.IsBackground = True readThread.Start() End Sub Public Property Username() As String Get Return mUsername End Get Set(ByVal value As String) mUsername = value End Set End Property Private Sub doRead() Const BYTES_TO_READ As Integer = 255 Dim readBuffer(BYTES_TO_READ) As Byte Dim bytesRead As Integer Dim sBuilder As New System.Text.StringBuilder Do bytesRead = mClient.GetStream.Read(readBuffer, 0, BYTES_TO_READ) If (bytesRead > 0) Then Dim message As String = System.Text.Encoding.UTF8.GetString(readBuffer, 0, bytesRead) If (message.IndexOf(MESSAGE_DELIMITER) > -1) Then Dim subMessages() As String = message.Split(MESSAGE_DELIMITER) 'The first element in the subMessages string array must be the last part of the current message. 'So we append it to the StringBuilder and raise the dataReceived event sBuilder.Append(subMessages(0)) RaiseEvent dataReceived(Me, sBuilder.ToString) sBuilder = New System.Text.StringBuilder 'If there are only 2 elements in the array, we know that the second one is an incomplete message, 'though if there are more then two then every element inbetween the first and the last are complete messages: If subMessages.Length = 2 Then sBuilder.Append(subMessages(1)) Else For i As Integer = 1 To subMessages.GetUpperBound(0) - 1 RaiseEvent dataReceived(Me, subMessages(i)) Next sBuilder.Append(subMessages(subMessages.GetUpperBound(0))) End If Else 'MESSAGE_DELIMITER was not found in the message, so we just append everything to the stringbuilder. sBuilder.Append(message) End If End If Loop End Sub Public Sub SendMessage(ByVal msg As String) Dim sw As IO.StreamWriter Try SyncLock mClient.GetStream sw = New IO.StreamWriter(mClient.GetStream) 'Create a new streamwriter that will be writing directly to the networkstream. sw.Write(msg) sw.Flush() End SyncLock Catch ex As Exception MessageBox.Show(ex.ToString) End Try 'As opposed to writing to a file, we DONT call close on the streamwriter, since we dont want to close the stream. End Sub End Class
So, couple of things ..... First of all: mentioned above decompiled code IS NOT RELATED to KMS activation at all!!! They are not SBOXes ... but fragments from precomputed keyschedule - every block of 256 bytes has all possible values 0..255 in mixed order, as result in every block will be exactly one '0' There (in sppsvc, osppsvc) are totally 3 similar hash functions with 3 different resulting keyschedules (however algos are identical) and only third of them is used in hash computation So don't waste your precious time Second: Signature algorithm itself is Rijndael based and works EXACTLY as i wrote in my previous posts. I can give full working C# code for KMS computations (really tested), but i don't think that publishing for general availability source code of this sort will be reasonable. So maybe PM And last .... in W8 KMS operations are ported from plugin library (sppobjs in W7) to special COM object proxy SppExtComObj (very interesting thing internally). P.S. in this proxy RPC KMS function semantics are slightly changed, but this seems be only due to use of more recent midl compiler About RPC comm - simple listening on tcp CAN be used because of very simple RPC req/resp with basic RPC packet parsing .. but this can be a little complicated .. how about mixed mode .net dll (can be coded in managed C++)?
@CODYQX4: Speaking about KMS RPC server - the most apropriate way to integrate it into C# app will be use of PInvoke interop. This is elegant way how to use Win32 API functions, only trouble can be callback function pointers in RPC structs .. Second acceptable approach can be full-blown C# RPC client/server protocol parser library, but, in my opinion, it's total overkill I'll try to do some experiments with this (i have large experience with PInvoke)...
You seem to have done a great part of the job ... Can you explain and point us to the correct functions (name it, it's help & everybody have IDA), corrects dlls... in some words: Share with us what you know about the processes ... For example, what is the role of SUB_58258D ? Thanks
Yep, RpcLibrary is PInvoke implementation too. And it is overkill for our target, KMS needs in about fourth part of RpcLibrary. I will compile KMS server/client interface in C++ with midl compiler and then port it to C#/PInvoke.
Yes that should be the better, smaller and less resource exhausting method. I do not call myself much of a coder, but if you can come up with something, please share
Just an idea for client emulation: Since KMS also activates downlevel clients, it's probably a good idea to analyze requests from Vista or 7, since these might use a simpler protocol than Windows 8.