相关链接
研究目的
马甲包过审,其中重要的一步是图片资源的混淆,如何处理图片, 才能欺骗苹果机审?于是网上能搜到的,无非是以下两种方式:
- 修改图片任意一点的像素,即可使得
MD5
不同。 - 对图片进行轻量压缩,可以修改图片的
hash
值。
是否有用,有待验证。
对于第一种方式,撸个脚本即可搞定:
import PIL.Image
import os
import random
errornum = 0
class changePixel:
def __init__(self,dir_path):
self.modifyFolder(dir_path,['.jpg','.png'])
print('转换失败 {} 个'.format(errornum))
def modifyFile(self,fileName):
global errornum
try:
img = PIL.Image.open(fileName)
width = img.size[0]
height = img.size[1]
randomx = random.randint(0, width - random.randint(0, 5))
randomy = random.randint(0, height - random.randint(0, 5))
randomvalue = random.randint(0, 255)
img.putpixel((randomx, randomy), randomvalue)
img.save(fileName)
print(fileName)
except:
print('---' + fileName)
errornum += 1
def modifyFolder(self,path,typeList):
for (root, dirs, files) in os.walk(path):
for filename in files:
print('++' + filename)
name = os.path.join(root, filename)
(filename, extension) = os.path.splitext(filename)
if extension in typeList:
self.modifyFile(name)
if __name__ == '__main__':
print('请输入图片所在路径:')
dir_path = input()
dir_path = str(dir_path).replace('\\','').strip()
changePixel(dir_path)
对于第二种方式,找到相关的文章:
安装ImageMagick
brew install ImageMagick
contrastImage作用:
1、指定size缩放图片
1)根据给定值和原比例缩放
#缩放到这个尺寸,实测图片原比例不变,小的一侧等于设定值,另一侧根据比例变化。
# 例如原图尺寸为3456 × 4608(3 : 4),缩放后为:300 x 400
convert -resize "300x500" input.jpg output.jpg
2)设定缩放标准,比 600x800 大则修改,比 600x800 小则不变
# 假如 input.jpg 尺寸为 300 x 400,比 600 x 800 小,output.jpg 仍为 300 x 400
# 可以防止比 600x800 小的图失真
convert -resize "600x800>" input.jpg output.jpg
3)根据指定比例缩放
# output.jpg 缩小为 input.jpg 的一半
convert -resize 50% input.jpg output.jpg
2、移除多余信息
记录图片一些描述信息。例如相机信息(光圈,相机型号)、photoshop元数据,颜色表等信息。它占用的空间可以从几KB到几百KB,甚至可能更大。
convert -strip input.jpg output.jpg
#或者:
convert +profile "*" input.jpg output.jpg
移除信息:
3、调节压缩比
convert -quality 75% input.jpg output.jpg
当然,以上几个指令,可以写成一条。
convert -resize 50% -quality 75% strip input.jpg output.jpg
如果是批量处理,可以这样写:
$ cd 目标文件夹
$ find . -iname "*.jpg" -exec echo {} \; -exec convert {} -quality 95 {} \;
有人说调节压缩比,可以修改图片hash
值,实测,发现并无影响,倒是MD5
发生变化:
def imagehashTest(self):
from PIL import Image
import imagehash
import hashlib
# 获得图片hash值
pic1 = '/Users/hncy-ios/Desktop/打包测试/222/111.jpg'
pic2 = '/Users/hncy-ios/Desktop/打包测试/222/222.jpg'
print('获取hash值:')
hash = imagehash.average_hash(Image.open(pic1))
print(hash)
hash2 = imagehash.average_hash(Image.open(pic2))
print(hash2)
if hash == hash2:
print('结果:hash值相同')
# 获取图片MD5值
print('获取MD5:')
fd = open(pic1, "rb")
data = fd.read()
fmd5 = hashlib.md5(data)
print(fmd5.hexdigest())
fd_2 = open(pic2, "rb")
data_2 = fd_2.read()
fmd5_2 = hashlib.md5(data_2)
print(fmd5_2.hexdigest())
结果如下:
获取hash值:
fc676e30e1e0f0b8
fc676e30e1e0f0b8
结果:hash值相同
获取MD5:
65dff8a1f7a2c1a23db4508ef7a208ed
345b8a3e87facb2f945dbb74f9579124
进一步搜索,发现这种方法获取的hash
值,学名叫感知哈希算法(Perceptual Hash Algorithm
)。
而有人说,压缩图片可以改变hash
值,其实说的只是加密哈希算法(Cryptographic Hash Algorithm
),通过以下方式,发现压缩前后的两张图的MD5
和SHA1
、SHA256
都是不同的值。
MD5
$ md5 文件路径
SHA1
$ shasum文件路径
或者
$ openssl dgst -sha1 文件路径
SHA256
openssl dgst -sha256 文件路径
MD5:
$ cd /Users/hncy-ios/Desktop/打包测试/222
$ md5 111.jpg
MD5 (111.jpg) = 65dff8a1f7a2c1a23db4508ef7a208ed
$ md5 222.jpg
MD5 (222.jpg) = 345b8a3e87facb2f945dbb74f9579124
SHA1:
$ shasum 111.jpg
70ff7786109099f4d8b5ade77388595a45cd2307 111.jpg
$ shasum 222.jpg
b08c6394e7557b28bec3bc7e8cec6017c8495973 222.jpg
SHA256:
$ openssl dgst -sha256 111.jpg
SHA256(111.jpg)= 82950bcd577540a6c91b32c4472287378b50282e759c5af955c9e402a634c09d
$ openssl dgst -sha256 222.jpg
SHA256(222.jpg)= 2444f3cef753cc2987bb2a69c0b4b6af68ced14a1fd0ee51fdbdbc5da578da68
那么,如果苹果用的是感知哈希算法,来区分资源的相似度,这可咋整?让我喝杯水中贵族百岁山,继续百度。。。
这是找到关于感知哈希算法的两篇:
如何避开感知哈希算法的方法没找到,倒是找到如何使用感知哈希算法。。。这不是为苹果出谋划策嘛?
Python
可以使用这个ImageHash来获取图片的感知哈希值。
这个库支持如下几种:
- average hashing (aHash)平均散列
- perception hashing (pHash)感知散列
- difference hashing (dHash)差异散列
- wavelet hashing (wHash)微波散列
感知哈希算法是一类算法的总称,包括 aHash、pHash、dHash。顾名思义,感知哈希不是以严格的方式计算 Hash 值,而是以更加相对的方式计算哈希值,因为“相似”与否,就是一种相对的判定。
- aHash:平均值哈希。速度比较快,但是常常不太精确。
- pHash:余弦感知哈希。精确度比较高,但是速度方面较差一些。
- dHash:差异值哈希。Amazing!精确度较高,且速度也非常快。
- wHash:微波哈希
本文中我们用到的是第一种
这里面也说到,感知哈希更适合用来判断两张图片相似度的合理性:
Why can we not use md5, sha-1, etc.?
Unfortunately, we cannot use cryptographic hashing algorithms in our implementation. Due to the nature of cryptographic hashing algorithms, very tiny changes in the input file will result in a substantially different hash. In the case of image fingerprinting, we actually want our similar inputs to have similar output hashes as well.
由于加密散列算法的性质,输入文件中的微小变化将导致大不相同的散列。感知哈希,可以理解为图像的指纹了。既然这样,我拿两张图片实践下,一张是微单直出图,另一张是该微单直出图用手机端的Snapseed
P过的。
获取hash值:
f177ffc885070612
fc676e30e1e0f0b8
获取MD5:
1ec1dd0f205d80611fe9c7ea0e60e8dd
65dff8a1f7a2c1a23db4508ef7a208ed
哟,指纹也是可以变化的嘛!
由于这张图片P过一段时间了,具体P了哪些忘记了,于是我又用同一种图片,P了一张新的出来,只调节对比度(对比度+10)。
获取hash值:
f177ffc885070612
ec676e30e1e0f0b8
获取MD5:
1ec1dd0f205d80611fe9c7ea0e60e8dd
8f7a9b1bf3c8887108540efa2d077187
发现P过的图,与原图的感知哈希值完全不同了,但是两张P图,之间的值倒是很类似:
- fc676e30e1e0f0b8
- ec676e30e1e0f0b8
从直观上来说,两次P过的差距不大,二者具有相似性还挺大的。
这种变化,会不会跟Snapseed
导出也有关系(导出时被压缩了?)?使用上面这张对比度+10的图,导入Snapseed
,再导出,对比他们的感知哈希值:
获取hash值:
ec676e30e1e0f0b8
ec676e30e1e0f0b8
可以看出,导入导出不影响原图的感知哈希值。
2019年05月07日更新
convert input.png -sigmoidal-contrast 5,50% output.png
结论
综上实测,ImageMagick
的缩放
,移除多余信息
、调节缩放比例
,这几种在适度范围内调节,不影响使用。但是,均不会对图片的感知哈希值产生影响!
因此,目前的认知,能改变图片的感知哈希值,只能通过修改图片可见的设置(对比度之类)。
添加垃圾图片资源,也许是一个有效的方式哦。