思考的结论:其实这种国际性的逆向比赛,肯定会考一些数学的知识,这个考的是比较基础了,无奈自己没有这个基础。
话说还是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 ofg
, then the congruence has no solutions (ifax + my = b
for some integersx
andy
, then any common divisor ofa
andm
must also be a divisor ofb
) -
if
b
is a multiple ofg
, then the congruence is exactly equivalent to(a/g)x = (b/g) (mod (m/g))
. Nowa/g
andm/g
are relatively prime, so we can compute an inverse toa/g
modulom/g
. Multiplying that inverse byb/g
gives a solution, and the general solution can be obtained by adding an arbitrary multiple ofm/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的第三部分了。
篇外:回去翻了一下离散数学,发现数论部分只讲到了同余,还没讲同余方程。我脑子里以前也是印象中有同余这么个概念,具体说不上来怎么用。
另外,就是大数运算需要学习一下,没有识别出来是在做大数运算。