Buenas tardes,
Se que puede parecer el tipico hilo donde pido que alguien me haga entero el trabajo o que me ayude a crackear un programa desconocido, pero quiero dar a entender que no es así.
El programa en cuestión, es un programa en el que uno pone una clave de licencia, genera un código, que tu tienes que mandar a la empresa, y este te devuelve un codigo de retorno.
La empresa en cuestión se ha ido al carajo, así que no existe y no se puede usar más que en los pc's que ya está instalado.
Habian 3 ordenadores, pero resulta que en uno cambiamos el disco duro, clonamos el sistema, y al ejecutar el programa resultó que no funcionaba asi que descompilandolo con .NET Reflector vi que el codigo que se generaba tomaba el num de serie del disco duro como parte para generar el código.
Todos los códigos se almacenan en el registro de Windows, pero antes de mirar ahi comprueba que concuerda, así que transportando las claves símplemente, no vale.
Mi gran problema, es que he podido descompilarlo (no es muy dificil con el .NET Reflector), intento coger los cachos que me son de utilidad de código para que me devuelva el código de retorno, pero el primer problema es que hay una linea:
buffer(i) = CByte(valor.Chars(i))
que luego en Visual Studio 2005 me dice que eso no puede ser, y tengo que usar Val o AsciW si no recuerdo mal, para hacer ese "casting".
Lo hago y bueno, sale un código y tal, lo pongo y no es el bueno, así que hice una traza, y dependiendo de qué funcion ponga (Val o AsciW), me devuelve un valor u otro, asi que me da por pensar que el programa por dentro, haciendo la linea esa, tambien me devuelve algo diferente, y por eso no soy capaz de averiguar la clave.
¿Sabeis que puede pasar o que puedo hacer para resolver esto?
No sé si me he equivocado de subforo, como no he visto algo de "cracking" concretamente puesto he ido al lenguaje en el que aparentemente está escrito el programa.
Puedo aportar todas las funciones y procedimientos que se encargan de generar el código, pero el programa en sí no puedo ya que se comunica con un servidor para generar estadísticas y comprometería la seguridad de mi empresa.
muchas gracias, y espero que alguien pueda ayudarme!
Esto deberia ir a la sección de .net (https://foro.elhacker.net/net-b62.0/)
Y para
buffer(i) = CByte(valor.Chars(i))
tenes Byte.Parse o Convert.ToByte :)
Buenas, siento haber tardado tantisimo en contestar... pero la uni no perdona.
EDITO: Despues de darle algunas vueltas, habia pensado en descompilar el .exe y cambiarle diréctamente desde el ensamblador la parte en la que controla el registro, y saltarme directamente la clave, o que imprima la clave en el registro en lugar de buscarlo, y se autoregistre, pero soy incapacisimo de encontrar un programa para hacerlo o en el caso de ollydbg, de hacer algo a derechas (el debug produce excepciones despues de llamar a sitios tan dispares como kernel o win32, jamas consigo que me saque el codigo de mi "discoverymail.exe"
No me funcionó el Parse ni el ToByte.
Hay un método que llama a un método de un objeto creado de la clase MD5 (ComputeHash) y le da, supuestamente, lo que mete buffer(i) = CByte(valor.Chars(i))
valor es una cadena que es como el código a darle a la "empresa" (que vuelvo a anticipar que ya no existe).
Estoy casi seguro de que es este método es el que lo lía todo, y no se si es que usa versiones anteriores/posteriores del framework .net y por eso esa linea en la compilacion de su momento era valida.
Como hice un codigo para hacer la traza de lo que iba haciendo para hallar el codigo de retorno (luego al verlo ineficaz busque que hiciese el mismo codigo que esto me retorna, sin exito), puedo pegarlo aquí sin comprometer a la empresa:
Código del fichero principal
Imports System.Security.Cryptography
Imports Microsoft.Win32
Public Class Form1
Shared idCompany As String = "30E35072EG3A"
Shared clave As String = "5GD72G5E9GE9"
Public Function GetDiscoveryMailConfigKey() As RegistryKey
Dim key As RegistryKey
Try
key = Registry.LocalMachine.OpenSubKey("Software").OpenSubKey("DiscoveryMail", True)
If (key Is Nothing) Then
key = Registry.LocalMachine.OpenSubKey("Software", True).CreateSubKey("DiscoveryMail")
End If
Catch obj As System.Exception
Return Nothing
End Try
Return key
End Function
Public Function GetCompany() As String
If (idCompany <> "") Then
Return idCompany
End If
Dim discoveryMailConfigKey As RegistryKey = Me.GetDiscoveryMailConfigKey
If (discoveryMailConfigKey Is Nothing) Then
MessageBox.Show("Error al acceder al registro. Compruebe que tenga permisos suficientes.")
Return ""
End If
If (Not discoveryMailConfigKey.GetValue("CompanyId") Is Nothing) Then
idCompany = CStr(discoveryMailConfigKey.GetValue("CompanyId"))
Return idCompany
End If
Return Me.SetCompanyId
End Function
Public Function SetCompanyId() As String
Dim discoveryMailConfigKey As RegistryKey = Me.GetDiscoveryMailConfigKey
If (discoveryMailConfigKey Is Nothing) Then
MessageBox.Show("Error al acceder al registro")
Return ""
End If
discoveryMailConfigKey.SetValue("CompanyId", idCompany)
Return idCompany
End Function
Public Function GetLicenseQuestion() As String
Dim serial As New HardDriveSerial
Return Me.md5((Me.GetCompany & "DiscoveryMail" & serial.Serial), 12)
End Function
Private Function toHex(ByVal a As Integer) As String
If (a < 10) Then
Return Convert.ToString(a)
End If
Select Case a
Case 10
Return "A"
Case 11
Return "B"
Case 12
Return "C"
Case 13
Return "D"
Case 14
Return "E"
End Select
Return "F"
End Function
Public Function CheckIsValidLicense(ByVal license As String) As Boolean
MessageBox.Show(Me.md5(("47619549" & Me.GetLicenseQuestion & "DiscoveryMail"), 12))
Return (Me.md5(("47619549" & Me.GetLicenseQuestion & "DiscoveryMail"), 12) = license)
End Function
Public Function md5(ByVal valor As String) As String
Return Me.md5(valor, 0)
End Function
Public Function md5(ByVal valor As String, ByVal length As Integer) As String
Dim md As MD5 = New MD5CryptoServiceProvider
Dim buffer As Byte() = New Byte(valor.Length - 1) {}
Dim i As Integer
For i = 0 To valor.Length - 1
'buffer(i) = CByte(valor.Chars(i)) El original
buffer(i) = CByte(AscW(valor.Chars(i))) 'El más adaptado al código
'buffer(i) = CByte(Byte.Parse(valor.Chars(i))) Lo del foro
Next i
Dim buffer2 As Byte() = md.ComputeHash(buffer)
Dim text As String = ""
Dim j As Integer
For j = 0 To buffer2.Length - 1
Dim num2 As Integer = buffer2(j)
Dim a As Integer = (num2 Mod &H10)
Dim num3 As Integer = (num2 / &H10)
text = (text & Me.toHex(a) & Me.toHex(num3))
Next j
If (text.Length > 0) Then
text = Me.reduceText(text, 12)
End If
Return text
End Function
Private Function reduceText(ByVal text As String, ByVal length As Integer) As String
Dim str As String = "0KAL1MBN2OCP3QDR4SET5UFV6WGX7YHZ8I9J"
Dim num4 As Integer = 0
Do While (text.Length > length)
Dim ch As Char = text.Chars((text.Length - 1))
text = text.Substring(0, (text.Length - 1))
Dim ch2 As Char = text.Chars(num4)
Dim index As Integer = str.IndexOf(ch2)
Dim num2 As Integer = str.IndexOf(ch)
Dim num3 As Integer = ((index + num2) Mod str.Length)
text = (text.Substring(0, num4) & str.Chars(num3) & text.Substring((num4 + 1), ((text.Length - num4) - 1)))
num4 += 1
If (num4 > length) Then
num4 = 0
End If
Loop
Return text
End Function
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAccept.Click
If (Me.txtLicencia.Text.Length = 12) Then
If Me.CheckIsValidLicense(Me.txtLicencia.Text) Then
Me.btnAccept.Enabled = True
Else
Me.btnAccept.Enabled = False
End If
End If
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Me.CheckIsValidLicense(Me.txtLicencia.Text)
MessageBox.Show(GetLicenseQuestion())
Me.Dispose()
End Sub
End Class
codigo es lo que estoy intentando sacar en el messagebox
Serial es esto:
Imports System.Management
Friend Class HardDriveSerial
' Methods
Public Function Serial() As String
Dim list As New ArrayList
'Dim coge As String = "None"
Dim searcher As New ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive")
Dim obj2 As ManagementObject
For Each obj2 In searcher.Get
Dim drive As New HardDrive
drive.Model = obj2.Item("Model").ToString
drive.Type = obj2.Item("InterfaceType").ToString
'coge = obj2.Item("Signature").ToString()
list.Add(drive)
Next
searcher = New ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMedia")
Dim num As Integer = 0
Dim obj3 As ManagementObject
For Each obj3 In searcher.Get
Dim drive2 As HardDrive = DirectCast(list.Item(num), HardDrive)
If (obj3.Item("SerialNumber") Is Nothing) Then
drive2.SerialNo = "None"
'drive2.SerialNo = coge
Else
drive2.SerialNo = obj3.Item("SerialNumber").ToString
End If
num += 1
Next
If (list.Count > 0) Then
Return DirectCast(list.Item(0), HardDrive).SerialNo
End If
Return "NoDisc"
End Function
End Class
Los comentarios evidentemente son mios,estaba sacando el numero de serie del disco duro de una forma alternativa a ver si era eso, pero ni sacandolo con Signature lo hace bien, luego probé con otro programa que lo saca tambien con WMI y tanto en este como ese programa externo ponia "None" asi que descarté este problema.
Y este es HardDrive
Friend Class HardDrive
' Properties
Public Property Model() As String
Get
Return Me.model2
End Get
Set(ByVal value As String)
Me.model2 = value
End Set
End Property
Public Property SerialNo() As String
Get
Return Me.serialNo2
End Get
Set(ByVal value As String)
Me.serialNo2 = value
End Set
End Property
Public Property Type() As String
Get
Return Me.type2
End Get
Set(ByVal value As String)
Me.type2 = value
End Set
End Property
' Fields
Private model2 As String
Private serialNo2 As String
Private type2 As String
End Class
Modifiqué las variables privadas y los Me.---- con ese 2 que se ve porque me decia algo de noseque recursivo, pero esta comprobado que pone y devuelve los valores bien
¿Algúna idea?