使用给定的密码反转编码的密钥 - 找出反转算法

逆向工程 解密
2021-06-20 20:34:21

所以我有一个古老的应用程序,该公司已经破产,我想我会看看它是如何运作的;它提供了一个密钥,并且需要给它一个密钥。这两个键都以某种方式编码,然后比较编码值的部分是否相等。首先,我将解释编码过程,因为我是在 javascript 中重新制作的

这似乎是某种形状或形式的凯撒密码,我很确定它等同于公式: C(x) = (P(b - a - x + 284) mod 26) + 48其中
x = 字符编号
b = 字母表中
当前字符索引a =字母表中的前一个字母索引

const alphabet = `SDHACENOIFKXQLBMPJTZURWVGY`

function encodeString(s) {
    var result = s.charAt(0),
        lastLetterIdx = alphabet.indexOf(s.charAt(0)) 

    for(let i = 0; i < s.length - 1; i++) {
        let thisLetterIdx = alphabet.indexOf(s.charAt(i + 1)) 
        let cypherNum = thisLetterIdx - lastLetterIdx - i
        cypherNum += 284
        let modNum = cypherNum % 26
        let encChar = String.fromCharCode(modNum + 48)

        result += encChar

        lastLetterIdx = thisLetterIdx
    }

    return result
}

软件提供的密钥
ALVMGRCTQQEYMNAHDANKPGKPO
被编码为
A87>4A26;@8833898:::;<?8B

然后通过跳过第一个字符并将 ascii 值相加来校验代码,因此在这种情况下,数字是 1378,mod 25 = 3,位置 3(索引为 0)的字母字符A与键的第一个字符匹配.

对于编码步骤 2,软件采用字符 1-12 (87>4A26;@883) 并通过以下方式将其编码为数字:

function encodedStringToNumber(str) {
    var number = 0,
        letterMulti = 1
    for(let i = str.length; i > 0; i--) {
        if(i < str.length)
            letterMulti = letterMulti * 19

        let letter = str.charCodeAt(i-1)
        letter -= 48
        letter *= letterMulti

        number += letter
    }
    return number
}

然后将数字转换为字符串并0填充左边以确保其长度为 15 个字符,然后用它的两半字符串连接数字以获得结果
979440403325666401568800000018

如果我们用我制作的随机测试密钥做同样的事情, VABCDEFGHIJKLMNOPQRSTUVWXYZABK
我们会得到一个加密的密钥,
V48<BHG7EFH7@>2;B4@;G661@>C88B
它像以前一样得到校验和,然后被转换为一个字符串,其中包含来自索引 1 的 11 个字符、来自索引 12 的 11 个字符和来自索引 23 的 7 个字符, 所以:

48<BHG7EFH7
@>2;B4@;G66
1@>C88B

我们将它们转换为数字,然后通过0再次填充左侧来确保字符串长度为 14、14 和 7 所以结果
2732684617734210265934650819588621338

我们现在将这个数字和软件中提供的数字拆分为一些关键元素并比较这些值。

假设密钥 A 是软件提供的密钥,979440403325666401568800000018密钥 B 是我随机使用的密钥2732684617734210265934650819588621338

从键 A 取字符(此处索引为 1):

3-4   (94)
28-29 (01)
6-7   (04)
8-9   (03)
10-15 (325666)
5     (4)
17-22 (015688)

从键 B 取:

3-4   (32)
1-2   (27)
29-30 (58)
15-16 (10)
31-36 (862133)
28    (9)
17-22 (265934)

这些值需要相同,并且添加的检查键 B 6-8 需要为“999”(我认为这是一个安装标志,000 是一个卸载标志)

因此,使用应用程序提供的密钥,我知道我需要制作一个加密为以下数字的密钥(其中 X 可以是任何数字):
0194x999xxxxxx03015688xxxxx404325666x

这个数字需要满足比较,将 999 放在正确的位置,当编码为字母时需要验证前面提到的校验和以及编码值的每个字母 >= '0',我的意思是 ascii 值是48 或以上。

我遇到的问题是它加密密钥的方式我一生都无法弄清楚他们如何制作一个相反的程序,如果我知道如何进行模算术,第一步似乎很容易,但是转换字母的数字直接超出我的范围。

1个回答

我随机写keygen: keygen('ALVMGRCTQQEYMNAHDANKPGKPO')

跑

GSFLOWZJOEWPOQFXFHVASFTPNBNTEJ      ->      G060?9@@7>684A8<712<2=<0A8A::8

060?9@@7>68           4A8<712<2=<            0A8A::8
01949999431597        030156882999840        43256662 (length 14 + 15 + 8 = 37)

0194999943159703015688299984043256662这满足0194x999xxxxxx03015688xxxxx404325666x :D

// example
keygen('ALVMGRCTQQEYMNAHDANKPGKPO')
// source
function keygen(code) {
 let indexes = [
  [3, 4, 28, 29,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,  5, 17, 18, 19, 20, 21, 22],
  [3, 4,  1,  2, 29, 30, 15, 16, 31, 32, 33, 34, 35, 36, 28, 17, 18, 19, 20, 21, 22]
 ]
 code = encodeString(code)
 let num = encodeNumber(code.substr(1, 12)).toString().padStart(15,0)+encodeNumber(code.substr(13, 12)).toString().padStart(15,0)
 let key = [...Array(37)].map((e,i)=>[5,6,7].indexOf(i) >= 0 ? '9' : Math.floor(Math.random()*10).toString())
 indexes[0].forEach((e,i)=>key[indexes[1][i]-1]=num[e-1]), key = key.join('')

 let result = decodeNumber(key.substr(0, 14)).padStart(11,0)+decodeNumber(key.substr(14, 15)).padStart(11,0)+decodeNumber(key.substr(29, 8)).padStart(7,0)
 return decodeString(sum(result,0)+result)
}

var alphabet = `SDHACENOIFKXQLBMPJTZURWVGY`
function encodeString(s) {
 let result = s.charAt(0), idx = alphabet.indexOf(s.charAt(0))
 for (let i=0; i<s.length-1; i++) {
  result += String.fromCharCode((alphabet.indexOf(s.charAt(i + 1))-idx-i+284)%26+48) 
  idx = alphabet.indexOf(s.charAt(i + 1))
 }
 return result
}
function decodeString(s) {
 let result = s.charAt(0), idx = alphabet.indexOf(s.charAt(0))
 for (let i=0; i<s.length-1; i++) {
  let num = (s.charCodeAt(i + 1) - 48)
  idx = [...alphabet].findIndex((x,y) => (y-idx-i+284)%26 == num)
  result += alphabet[idx]
 }
 return result
}
function encodeNumber(s) {
 let n = 0, l = 1
 for (let i=s.length; i>0; i--) {
  let c = (s.charCodeAt(i-1)-48)*l
  n += c, l *= 19
 }
 return n
}
function decodeNumber(n) {
 let c = 0, s = []
 for (let i=0; c != n; i++) {
  let v = (n % 19**(i+1))
  s.push((v-c)/19**i+48)
  c = v
 }
 return String.fromCharCode.apply(null, s.reverse())
}
function sum(s, idx = 1) {
 let cs = 0
 for (; idx < s.length; idx++) cs+=s.charCodeAt(idx)
 return alphabet[cs%25]
}