Descompilar / Desensamblar programa .NET

Iniciado por angel9484, 16 Noviembre 2010, 15:50 PM

0 Miembros y 1 Visitante están viendo este tema.

angel9484

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!

raul338

Esto deberia ir a la sección de .net

Y para

buffer(i) = CByte(valor.Chars(i))

tenes Byte.Parse o Convert.ToByte :)

angel9484

#2
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
Código (vbnet) [Seleccionar]

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:
Código (vbnet) [Seleccionar]
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
Código (vbnet) [Seleccionar]
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?