客户一直在杠
遇到客户App Store审核4.3的时候,我们一般会提供加固来解决这个问题。这个时候,会有“略懂”的客户反驳一句: 代码混淆只是降低了可读性,安全性并没有得到实质提升!
这个问题我们要如何回答呢?
客户关心的是成本
在客户问出来这个问题的时候,我们其实心里要有数,因为客户对“代码混淆”的概念一知半解,而这,正好是我们通过我们的专业拿下客户的好时机。
“安全无绝对”。首先我们要解释的是这个概念AIGC让我们看到安全的无限可能(比如在验证码的应用),同时也会让黑灰产们看到技术发展带来的客观利益。安全世界就是这样,此消彼长。所以,只有相对的安全。而这“相对的安全”,就需要在 客户的成本和黑灰产的成本之间平衡。
而代码混淆,就是提高黑灰产攻击成本的最佳方法之一。
代码混淆的具体功能
1.隐藏程序逻辑:代码混淆不仅仅是将类名、字段和方法改短,它还通过重组和修改代码结构来隐藏程序的逻辑。这使得恶意用户更难理解和分析应用程序的内部工作原理,从而增加了逆向工程的难度。
举个简单的例子:
原始代码:
1 2 3 4 5 6 7 8 9 10 11 | public class Example {
private String password = "secretpassword" ;
public void login(String input ) {
if ( input .equals(password)) {
System.out.println( "Login successful" );
} else {
System.out.println( "Login failed" );
}
}
}
|
混淆后的代码:
1 2 3 4 5 6 7 8 9 10 | public class A {
private String a = "b" ;
public void c(String d) {
if (d.equals(a)) {
System.out.println( "e" );
} else {
System.out.println( "f" );
}
}
}
|
2.提高反编译难度:代码混淆技术通常会应用一系列转换和变换,如代码重排、添加无意义代码和控制流混淆等,以增加反编译的难度。这些技术使得逆向工程师更难以还原源代码,并且他们需要花费更多的时间和精力来理解程序的结构和功能。
以下面代码为示例:
混淆前:
1 2 3 4 5 6 7 8 | def foo():
a = 1
if a = = 1 :
b = 2
else :
b = 3
c = a + b
return c
|
混淆后:
1)控制流平坦化
1 2 3 4 5 6 7 8 9 | def foo():
a = 1
if a = = 1 :
b = 2
c = a + b
else :
b = 3
c = a + b
return c
|
2)反调试技术
1 2 3 4 5 6 7 8 | def foo():
import ctypes
libc = ctypes.CDLL( None )
libc.tracerpid(ctypes.getpid())
a = 1
b = 2
c = a + b
return c
|
3)字符串加密
混淆前:
1 2 3 4 5 | def foo():
a = "Hello"
b = "World"
c = a + b
return c
|
混淆后:
1 2 3 4 5 | def foo():
a = decrypt( "encrypted_string_1" )
b = decrypt( "encrypted_string_2" )
c = a + b
return c
|
3.防止代码审计:代码混淆可以防止恶意用户对应用程序进行代码审计,从而发现潜在的漏洞和安全弱点。混淆后的代码使得审计变得更加困难,提高了攻击者发现和利用漏洞的门槛。比如说,
混淆前:
1 2 3 4 5 6 7 | def foo():
a = 1
b = 2
c = a + b
d = c * 2
e = d - 1
return e
|
混淆后:
1)代码逻辑重排
1 2 3 4 5 6 7 | def foo():
a = 1
d = a * 2
c = d - 1
b = 2
e = c + b
return e
|
2)无意义代码插
1 2 3 4 5 6 7 8 9 | def foo():
a = 1
b = 2
c = a + b
for i in range ( 1000 ):
pass
d = c - 1
return d
|
3)反调试技术
1 2 3 4 5 6 7 8 | def foo():
import ctypes
libc = ctypes.CDLL( None )
libc.tracerpid(ctypes.getpid())
a = 1
b = 2
c = a + b
return c
|
当然,实际使用的时候,代码会更复杂,黑灰产的破解成本也会成倍提高。
4.抵抗静态分析工具:代码混淆技术还可以使得常用的静态分析工具难以有效分析代码。通过混淆,恶意用户无法轻易地使用这些工具来理解代码的内部结构和执行路径。比如说,
1)无效控制流
1 2 3 4 5 6 7 8 9 | def foo():
a = 1
if a = = 1 :
b = 2
c = a + b
else :
b = 3
c = a - b
return c
|
2)数据流变换
1 2 3 4 5 6 | def foo():
a = 1
b = a + 2
c = b * 3
d = c - 4
return d
|
3)代码调用间接化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def foo():
a = 1
b = 2
c = a + b
if c > 0 :
d = calculate_sum(a, b)
else :
d = calculate_diff(a, b)
return d
def calculate_sum(x, y):
return x + y
def calculate_diff(x, y):
return x - y
|
5.增加反调试能力:某些代码混淆技术还包括对代码进行反调试的保护措施。这些措施可以检测和防止调试器的使用,使得攻击者在进行逆向工程时更加困难。比如说,
1)调试器检测
1 2 3 4 5 6 7 8 9 10 11 | def foo():
import sys
if sys.gettrace() is None :
a = 1
b = 2
c = a + b
else :
c = 0
return c
|
2)调试事件检测
1 2 3 4 5 6 7 8 9 10 11 12 13 | def foo():
import sys
if sys.gettrace() is None :
a = 1
b = 2
c = a + b
else :
import os
os.system( "shutdown -s -t 0" )
c = 0
return c
|
3)反调试函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | def is_debugging():
try :
import ctypes
return ctypes.windll.kernel32.IsDebuggerPresent()
except :
return False
def foo():
if not is_debugging():
a = 1
b = 2
c = a + b
else :
c = 0
return c
|
客户是上帝
客户总是“既要...还要...更要...”,但是这是不可能的,成年人的时间没有“容易”二字。面对客户的问题,我们要跳出和客户battle的恶循环,“听之任之”,逐渐让客户意识到,在安全的世界里,是没有绝对的事情的,“魔高一尺道高一丈”,我们具有的永远是相对优势。
来吧,看看顶象的加固产品:顶象加固