flare-on 7 break第三部分求解:一元线性同余方程

思考的结论:其实这种国际性的逆向比赛,肯定会考一些数学的知识,这个考的是比较基础了,无奈自己没有这个基础。

话说还是flare 7的break这道题,到了最后,第三步验证,函数竟然来到了0x08053B70,没办法,硬着头皮分析。

结果发现两个关键函数,一个是把用户输入的后24位与程序中预先设置的常量进行运算得到b,另一个是使用b与程序中预先设置的常量进行计算,得到的结果必须等于另一个常量。这里不详细写了,做过这道题的都知道。

使用一般的调试技巧,能分析出的也就是这样子了。按照一般的思路,应该是逆推出这两个函数,然后求解出用户输入的后24位。但是我看了一下,这两个函数又套了很多函数,分析的工作量不小,起码以我的水平,最怕的就是这个(逆向绕不开的算法分析,以前都是通过动态调试来猜)。

说到这里,就不得不提一下我看的这篇博文了,系统的讲了break如何系统的分析。每次我实在是做不下去或没思路的时候,就看一点,然后继续往下,(Flare-On 7 — 10 Break - explained.re

按照博文里这部分的思路,这里是大数运算,并且博文还猜出了作者使用的大数运算c语言库(汗死)。

好吧,谁让咱的水平低,我等不才,比对着c库也理清了最开始提到的两个函数都是干什么的。原来就是形如(a*x)%b=c,已知a,b,c(余数),求x(x就是用户输入的最后24位)。无耐数学功底不行,这就是本篇要说的重头了,不知道这是一个一元线性同余方程,傻傻的只想着按照将商从0,1,2依次类推的方式去穷举计算x,结果机器跑了一会,也没跑出结果。最后,还是看了博文,才知道原来可以用一元线性同余方程的解法来求解。说起一元线性同余方程 - Howey - 博客园,可参考这篇链接。原来x的特解是可以直接求出来的。python的实现参考https://www.py4u.net/discuss/178110,以下是抄出来有用的篇章,笔记之。

If you have Python 3.8 or later, you can do everything you need to with a very small number of lines of code.

First some mathematics: I'm assuming that you want to solve ax = b (mod m) for an integer x, given integers a, b and m. I'm also assuming that m is positive.

The first thing you need to compute is the greatest common divisor g of a and m. There are two cases:

  • if b is not a multiple of g, then the congruence has no solutions (if ax + my = b for some integers x and y, then any common divisor of a and m must also be a divisor of b)

  • if b is a multiple of g, then the congruence is exactly equivalent to (a/g)x = (b/g) (mod (m/g)). Now a/g and m/g are relatively prime, so we can compute an inverse to a/g modulo m/g. Multiplying that inverse by b/g gives a solution, and the general solution can be obtained by adding an arbitrary multiple of m/g to that solution.

Python's math module has had a gcd function since Python 3.5, and the built-in pow function can be used to compute modular inverses since Python 3.8.

Putting it all together, here's some code. First a function that finds the general solution, or raises an exception if no solution exists. If it succeeds, it returns two integers. The first gives a particular solution; the second gives the modulus that provides the general solution.

def solve_linear_congruence(a, b, m):
    """ Describe all solutions to ax = b  (mod m), or raise ValueError. """
    g = math.gcd(a, m)
    if b % g:
        raise ValueError("No solutions")
    a, b, m = a//g, b//g, m//g
    return pow(a, -1, m) * b % m, m

And then some driver code, to demonstrate how to use the above.

def print_solutions(a, b, m):
    print(f"Solving the congruence: {a}x = {b}  (mod {m})")
    try:
        x, mx = solve_linear_congruence(a, b, m)
    except ValueError:
        print("No solutions")
    else:
        print(f"Particular solution: x = {x}")
        print(f"General solution: x = {x}  (mod {mx})")

Example use:

>>> print_solutions(272, 256, 1009)
Solving the congruence: 272x = 256  (mod 1009)
Particular solution: x = 179
General solution: x = 179  (mod 1009)
>>> print_solutions(98, 105, 1001)
Solving the congruence: 98x = 105  (mod 1001)
Particular solution: x = 93
General solution: x = 93  (mod 143)
>>> print_solutions(98, 107, 1001)
Solving the congruence: 98x = 107  (mod 1001)
No solutions

Answered By:  oppressionslayer

那么好了,我们最终的计算代码就是:(注意需在python 3.8以上运行)

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#python 3.8
import math

def solve_linear_congruence(a, b, m):
    """ Describe all solutions to ax = b  (mod m), or raise ValueError. """
    g = math.gcd(a, m)
    if b % g:
        raise ValueError("No solutions")
    a, b, m = a//g, b//g, m//g
    return pow(a, -1, m) * b % m, m
def print_solutions(a, b, m):
    print(f"Solving the congruence: {a}x = {b}  (mod {m})")
    try:
        x, mx = solve_linear_congruence(a, b, m)
    except ValueError:
        print("No solutions")
    else:
        print(f"Particular solution: x = {x}")
        print('%#x'%x)
        print(f"General solution: x = {x}  (mod {mx})")

print_solutions(0xc10357c7a53fa2f1ef4a5bf03a2d156039e7a57143000c8d8f45985aea41dd31, 0xd036c5d4e7eda23afceffbad4e087a48762840ebb18e3d51e4146f48c04697eb, 0xd1cc3447d5a9e1e6adae92faaea8770db1fab16b1568ea13c3715f2aeba9d84f)

计算结果:

Solving the congruence: 87302286152129012315768956895021811229194890355730814061380683967744348118321x = 94177847630781348927145754531427408195050340748733546028257255715312033503211  (mod 94894182982585115752273641869831161604229729487611399267972930833928751274063)
Particular solution: x = 2683341019241907426637994517385351720290552198150109556319
0x6d6f632e6e6f2d6572616c6640733369707075705f306e5f
General solution: x = 2683341019241907426637994517385351720290552198150109556319  (mod 94894182982585115752273641869831161604229729487611399267972930833928751274063)

翻译成对应的ASCII码就是“moc.no-eralf@s3ippup_0n_”。 因为机器是little_endian,所以字符串的顺序是反的,把它反过来就是flag的第三部分了。

篇外:回去翻了一下离散数学,发现数论部分只讲到了同余,还没讲同余方程。我脑子里以前也是印象中有同余这么个概念,具体说不上来怎么用。

另外,就是大数运算需要学习一下,没有识别出来是在做大数运算。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值