016
upx壳用下载的upx直接脱壳命令为 upx -d 文件名

暴力破解
查找字符串锁定验证成功弹窗实现的汇编语言块,并在跳转成功和失败的命令前下断点


随便输入,运行发现没经过断点直接弹出验证失败弹窗,对执行跳转失败弹窗进行查找引用,发现大量跳转语句,跟踪发现这些都是验证序列号不符合就直接跳转失败页面。


将程序放进ida里分析找到444B30函数,只有跳转LABEL_23才会显示失败,向上找到跳转语句

LABEL_19疑似判断输入的序列号长度和部分位置检验,构造111-222-333(或者11-222-33、11-222-333)序列号重新调试发现可以到达失败弹窗前的断点。



初步推测序列号格式为111-222-333(或者11-222-33、11-222-333),将445322处直接改成jmp,即可爆破



序列号只能由数字和‘-’组成
在ida中可以看到很多参数或者函数前都有Sysutils::,System::,Dialogs::,它们是Borland C++ Builder 和 Delphi 编译器特有的命名空间和类库前缀。含义为System:: – 系统核心命名空间,Sysutils:: – 系统工具命名空间,Dialogs:: – 对话框命名空间
继续分析算法,发现先是对输入的序列号提取出数字,再将位数为9(10,11)为的序列号分别对每一位求7次幂(8次、9次幂)再相加,将和与提取出的字符按照顺序拼成的整数进行对比,这就是一个广义阿姆斯特朗数变种,幂次 = 位数本身。可以制作keygen如下:
def find_narcissistic_numbers(num_digits):
"""
Find numbers where the sum of each digit raised to the power of num_digits equals the number itself
"""
results = []
power = num_digits
start = 10 ** (num_digits – 1)
end = 10 ** num_digits
print(f"Searching {num_digits}-digit numbers (power={power})…")
for num in range(start, end):
digits = [int(d) for d in str(num)]
total = sum(d ** power for d in digits)
if total == num:
results.append(num)
return results
def format_serial(number, num_digits):
"""Format as xx-xxx-xx or xxx-xxx-xxx etc."""
s = str(number).zfill(num_digits)
if num_digits == 7:
return f"{s[:2]}-{s[2:5]}-{s[5:]}"
elif num_digits == 8:
return f"{s[:2]}-{s[2:5]}-{s[5:]}"
else:
return f"{s[:3]}-{s[3:6]}-{s[6:]}"
def generate_all_serials():
"""Generate all possible valid serial numbers"""
all_keys = []
for digits in [7, 8, 9]:
numbers = find_narcissistic_numbers(digits)
for num in numbers:
serial = format_serial(num, digits)
all_keys.append(serial)
print(f"Found: {serial} (number={num})")
return all_keys
if __name__ == "__main__":
print("Searching for all valid serial numbers…\\n")
keys = generate_all_serials()
print(f"\\nTotal found: {len(keys)} valid serial numbers:")
for k in keys:
print(k)

将生成的几位序列号进行验证发现通过,算法分析结束。


