前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >脚本代码混淆-Python篇-pyminifier(2)

脚本代码混淆-Python篇-pyminifier(2)

作者头像
七夜安全博客
发布于 2019-11-06 06:26:19
发布于 2019-11-06 06:26:19
3.7K00
代码可运行
举报
文章被收录于专栏:七夜安全博客七夜安全博客
运行总次数:0
代码可运行

微信公众号:七夜安全博客 关注信息安全技术、关注 系统底层原理。问题或建议,请公众号留言。

前言

上文中,我们讲解了pyminifier中简化和压缩代码的功能。本篇作为第二篇,也是最终篇,讲解一下最重要的功能:代码混淆,学习一下这个项目的混淆策略。大家如果觉得不错的话,一定要分享到朋友圈哈,写了快5000字,基本上每一个细节都给大家拆分出来了,贴了一部分关键代码,会长一些,一定要有耐心哟。

一.混淆效果

在讲解混淆策略之前,先看一下混淆的效果,恶不恶心,哈哈。对比着混淆的结果,再结合我的讲解,会理解地更加深入。

原始代码

专门设计了一段代码,基本上涵盖了经常出现的语法内容。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import io
import tokenize

abvcddfdf = int("10")
def enumerate_keyword_args(tokens=None):
    keyword_args = {}
    inside_function = False
    dsfdsf,flag = inside_function,1
    a = str(flag)
    for index, tok in enumerate(tokens):
        token_type = tok[0]
        token_string = tok[1]
        a = str(token_string)
        b=a
        if token_type == tokenize.NAME:
            if token_string == "def":
                function_name = tokens[index+1][1]
                keyword_args.update({function_name: []})
            elif inside_function:
                if tokens[index+1][1] == '=': # keyword argument
                    print(api(text=token_string))
                    keyword_args[function_name].append(token_string)
def api(text):
    print(text)

def listified_tokenizer(source):
    io_obj = io.StringIO(source)
    return [list(a) for a in tokenize.generate_tokens(io_obj.readline)]

code = u'''
def api(text):
    print(text)
'''
abcd=1212
bcde=abcd
cdef=(abcd,bcde)
defg=[abcd,bcde,cdef]
efgh = {abcd:"cvcv","b":"12121"}
f12212="hhah"
f112122="hheeereah"
tokens_list = listified_tokenizer(code)
print(tokens_list)
enumerate_keyword_args(tokens_list)

混淆后的效果

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!/usr/bin/env python
#-*- coding:utf-8 -*-=int
ݽ=None
ﮄ=False
ﻟ=str
嬯=enumerate
눅=list
import io
ﭢ=io.StringIO
import tokenize
ﰅ=tokenize.generate_tokens
ނ=tokenize.NAME= ("10")
def ܪ(tokens=ݽ):= {}= ﮄ
    dsfdsf,flag =,1
    a = (flag)
    for, tok in (tokens):= tok[0]= tok[1]
        a = ()
        b=a
        if== ނ:
            if== "def":= tokens[+1][1].update({: []})
            elif ﭷ:
                if tokens[+1][1] == '=': # keyword argument
                    print(ݖ(text=))[].append()
def ݖ():
    print()

def (source):
    د = (source)
    return [(a) for a in (د.readline)]= u'''
def api(text):
    print(text)
'''
횗=1212=횗
ﲊ=(,)=[,,]= {:"cvcv","b":"12121"}="hhah"="hheeereah"= ()
print()
ܪ()

二.混淆策略

pyminifier的混淆策略分成五大部分,主要是针对变量名,函数名,类名,内置模块名和外部模块进行混淆。每种混淆又分成两步,第一步是确定要混淆的内容,第二步进行内容替换,替换成随机字符。

1.变量名混淆

针对变量名的混淆,并不是所有变量名都能混淆的,因为要保证安全性,混淆过头了,程序就无法运行了。在 函数obfuscatable_variable对变量名进行了过滤,保留着可以混淆的变量名。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def obfuscatable_variable(tokens, index, ignore_length=False):

    tok = tokens[index]
    token_type = tok[0]
    token_string = tok[1]
    line = tok[4]
    if index > 0:
        prev_tok = tokens[index-1]#获取上一个Token
    else: # Pretend it's a newline (for simplicity)
        prev_tok = (54, '\n', (1, 1), (1, 2), '#\n')
    prev_tok_type = prev_tok[0]
    prev_tok_string = prev_tok[1]
    try:
        next_tok = tokens[index+1]#获取下一个Token
    except IndexError: # Pretend it's a newline
        next_tok = (54, '\n', (1, 1), (1, 2), '#\n')
    next_tok_string = next_tok[1]
    if token_string == "=":# 跳过赋值 = 后面的token
        return '__skipline__'
    if token_type != tokenize.NAME:#不是变量名称忽略
        return None # Skip this token
    if token_string.startswith('__'):## __ 开头的不管,比如__init__
        return None
    if next_tok_string == ".":# 导入的模块名(已经导入的)忽略
        if token_string in imported_modules:
            return None
    if prev_tok_string == 'import':#导入的包名忽略
        return '__skipline__'
    if prev_tok_string == ".":#导入模块中的变量/函数忽略
        return '__skipnext__'
    if prev_tok_string == "for":#for循环中的变量如果长度大于2则进行混淆
        if len(token_string) > 2:
            return token_string
    if token_string == "for":# for 关键字忽略
        return None
    if token_string in keyword_args.keys():#函数名忽略
        return None
    if token_string in ["def", "class", 'if', 'elif', 'import']:#关键字忽略
        return '__skipline__'
    if prev_tok_type != tokenize.INDENT and next_tok_string != '=':
        return '__skipline__'
    if not ignore_length:
        if len(token_string) < 3:#长度小于3个则忽略
            return None
    if token_string in RESERVED_WORDS:#在保留字中也忽略
        return None
    return token_string

从函数中可以看到,有以下几类变量名不能混淆:

  1. token属性不是tokenize.NAME的过滤掉,例如数字token,字符串token,符号token。
  2. 以 __ 开头的名称过滤掉,例如 init
  3. 导入的第三方的模块名和变量过滤掉,例如 import os,os不能修改。
  4. for循环中的变量名长度小于等于2的过滤掉。
  5. 函数名过滤掉(接下来会有专门针对函数的处理方式)。
  6. 关键字和保留字过滤掉,长度小于3的名称也过滤掉。

确定了要混淆的内容,接下来进行替换,主要涉及replace_obfuscatablesobfuscate_variable函数,核心代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if token_string == replace and prev_tok_string != '.':# 不是导入的变量
        if inside_function:#在函数里面
            if token_string not in keyword_args[inside_function]:#判断是否在参数列表中
                if not right_of_equal: #token所在的这一行没有 = 或者token在 = 的左边
                    if not inside_parens: # token不在( )之间
                        return return_replacement(replacement) # 例如 a=123 ,str.length() 中的str
                    else:
                        if next_tok[1] != '=':# token在( )之间  api(text) 中的 text,
                            return return_replacement(replacement)
                elif not inside_parens:#token在 = 的右边,token不在( )之间   例如 a = b 中的b
                    return return_replacement(replacement)
                else:#token在 = 的右边,token在( )之间
                    if next_tok[1] != '=': #例如a=api(text) text需要改变
                        return return_replacement(replacement)
        elif not right_of_equal:#token所在的这一行没有 = 或者token在 = 的左边
            if not inside_parens:
                return return_replacement(replacement)
            else:
                if next_tok[1] != '=':
                    return return_replacement(replacement)
        elif right_of_equal and not inside_parens:# 例如 a = b 中的b
            return return_replacement(replacement)

在上述代码中可以看出,混淆变量名称需要区分作用域,即模块中的变量和函数中的变量,即使名称是一样的,但不是一回事,所以需要区分对待。通过如下三个变量进行划分:

  • inside_function 代表变量是在函数中
  • right_of_equal 代表着变量是在 = 的右侧
  • inside_parens 代表变量是在()中

大家可能奇怪,right_of_equal 和 inside_parens 是用来干什么的?其实是为了区分函数调用使用参数名的情况。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def api(text):
    print(text)

api(text="123")

在函数调用的时候, api(text="123")中的text是不能混淆的,不然会报错的。

2.函数名混淆

通过obfuscatable_function函数确定要混淆的函数名称,原理上很简单,排除类似_init_的函数,然后前一个token是def,那当前的token就是函数名称。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def obfuscatable_function(tokens, index, **kwargs):
     ......
    prev_tok_string = prev_tok[1]
    if token_type != tokenize.NAME:
        return None # Skip this token
    if token_string.startswith('__'): # Don't mess with specials
        return None
    if prev_tok_string == "def": #获取函数名称
        return token_string

对于函数名称的替换主要是在两个部位,一个是函数定义的时候,另一个是在函数调用的时候。函数定义的时候容易确定,函数调用的时候大体分成两种情况,一种是静态函数,另一种是动态函数,主要是要确认一下是否需要替换。具体代码位于obfuscate_function函数中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def obfuscate_function(tokens, index, replace, replacement, *args):

    def return_replacement(replacement):
        FUNC_REPLACEMENTS[replacement] = replace
        return replacement
          ......
    if token_string.startswith('__'):
        return None
    if token_string == replace:
        if prev_tok_string != '.':
            if token_string == replace: #函数定义
                return return_replacement(replacement)
        else:#函数调用
            parent_name = tokens[index-2][1]
            if parent_name in CLASS_REPLACEMENTS:#classmethod
                # This should work for @classmethod methods
                return return_replacement(replacement)
            elif parent_name in VAR_REPLACEMENTS:#实例函数
                # This covers regular ol' instance methods
                return return_replacement(replacement)

在代码的末尾 通过prev_tok_string来判断是定义函数还是调用,如果prev_tok_string!=“.”,代表着定义。

通过parent_name是否在CLASS_REPLACEMENTS VAR_REPLACEMENTS中,判断是静态函数还是动态函数,但是写的有点冗余,最后的处理方式都是一样的。

3.类名混淆

通过obfuscatable_class函数来确认要混淆的类名称,只要判断 prev_tok_string=="class" 即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def obfuscatable_class(tokens, index, **kwargs):
    ......
    prev_tok_string = prev_tok[1]
    if token_type != tokenize.NAME:
        return None # Skip this token
    if token_string.startswith('__'): # Don't mess with specials
        return None
#通过判断前一个token是class,就可以知道当前的是类名称
    if prev_tok_string == "class":
        return token_string

对于类名称的替换,这个项目进行了简化处理,无法跨模块跨文件进行混淆,这样的设定就简单了很多,关键代码在obfuscate_class函数中,其实直接就替换了,没啥复杂的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def obfuscate_class(tokens, index, replace, replacement, *args):

    def return_replacement(replacement):
        CLASS_REPLACEMENTS[replacement] = replace
        return replacement
    ......
    if prev_tok_string != '.': ##无法跨模块混淆
        if token_string == replace:
            return return_replacement(replacement)

4.builtin模块混淆

首先遍历token发现内置模块中的函数和类,代码中内置了 builtins表,enumerate_builtins函数通过比对里面的值来确定token是否是内置的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
builtins = [
    'ArithmeticError',
    'AssertionError',
    'AttributeError',
    ......
    'str',
    'sum',
    'super',
    'tuple',
    'type',
    'unichr',
    'unicode',
    'vars',
    'xrange',
    'zip'
]

内置模块的混淆通过赋值的方式来实现,举个例子,在Python 中有个str的内置函数,正常代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
sum = str(10)

混淆后:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
xxxx= str
sum = xxxx(19)

原理如上所示,具体是通过obfuscate_builtins函数来实现的,将所有符合的内置函数/类,都转化成赋值等式,插入到token链的前面,但是有一点需要注意:新的token必须要放到解释器路径(#!/usr/bin/env python)和编码('# -- coding: utf-8 --')之后,这样才不会报错。代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for tok in tokens[0:4]: # Will always be in the first four tokens
        line = tok[4]
        if analyze.shebang.match(line): # (e.g. '#!/usr/bin/env python')
            if not matched_shebang:
                matched_shebang = True
                skip_tokens += 1
        elif analyze.encoding.match(line): # (e.g. '# -*- coding: utf-8 -*-')
            if not matched_encoding:
                matched_encoding = True
                skip_tokens += 1
    insert_in_next_line(tokens, skip_tokens, obfuscated_assignments)

5.第三方模块与函数的混淆

针对第三方模块与函数的混淆,pyminifier进行了简化处理,具体逻辑在obfuscate_global_import_methods中,通过以下两种方式导入的模块忽略:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import xxx as ppp
from xxx import ppp

只处理 importpackage类型的导入。

枚举模块

首先通过 enumerate_global_imports 函数枚举所有通过import导入的模块,忽略了类里面和函数中导入的模块,只接受全局导入,核心代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
elif token_type == tokenize.NAME:
            if token_string in ["def", "class"]:
                function_count += 1
            if indentation == function_count - 1: #出了函数之后才会相等
                function_count -= 1
            elif function_count >= indentation: #排除了在函数内部和类内部的import导入
                if token_string == "import":
                    import_line = True
                elif token_string == "from":
                    from_import = True
                elif import_line:
                    if token_type == tokenize.NAME  and tokens[index+1][1] != 'as':# 排除 import as
                        if not from_import and token_string not in reserved_words:#排除from import
                            if token_string not in imported_modules:
                                if tokens[index+1][1] == '.': # module.module
                                    parent_module = token_string + '.'
                                else:
                                    if parent_module:
                                        module_string = (
                                            parent_module + token_string)
                                        imported_modules.append(module_string)
                                        parent_module = ''
                                    else:
                                        imported_modules.append(token_string)
遍历函数并混淆

获取导入的模块后,接着遍历token,获取源文件中模块调用的函数,和之前的方法一样通过赋值的方式进行替换,举个例子:原代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import os
os.path.exists("text")

混淆后的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import os
ﳀ=os.path
ﳀ.exists("text")

具体函数调用的替换代码很简短,module_method形如os.path,即ﳀ.exists("text")这部分:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if token_string == module_method.split('.')[0]:
    if tokens[index+1][1] == '.':
        if tokens[index+2][1] == module_method.split('.')[1]:
            tokens[index][1] = replacement_dict[module_method]
            tokens[index+1][1] = ""
            tokens[index+2][1] = ""

接下来将替换变量进行定义,形如ﳀ=os.path,并通过insert_in_next_line函数插入到import模块的下方。有一点需要注意的是token索引index + 6,原因很简单, ﳀ=os.path\n转化为token的长度就是6。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
elif import_line:
    if token_string == module_method.split('.')[0]:
        # Insert the obfuscation assignment after the import
        ......
        else:
            line = "%s=%s\n" % ( # This ends up being 6 tokens
                replacement_dict[module_method], module_method)
        for indent in indents: # Fix indentation
            line = "%s%s" % (indent[1], line)
            index += 1
        insert_in_next_line(tokens, index, line)
        index += 6 # To make up for the six tokens we inserted
index += 1

混淆源生成

从上面讲解的混淆策略中,我们大体了解了pyminifier的工作方式,但是还有一点没有讲解,那就是混淆源的生成,什么意思呢?如下所示, os.path为啥会被替换成

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
=os.path

混淆源生成位于obfuscation_machine函数中,分成了两种情况。

在Py3中,支持unicode字符作为变量名称,所以基本上是使用unicode字符作为数据源,混淆后会出现各个国家的语言符号,看着着实恶心,而Py2则是使用的ASCII码的大小写作为数据源。数据源有了,然后进行随机化,让其变得更混乱一些。

代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# This generates a list of the letters a-z:
    lowercase = list(map(chr, range(97, 123)))
    # Same thing but ALL CAPS:
    uppercase = list(map(chr, range(65, 90)))
    if use_unicode:
        # Python 3 lets us have some *real* fun:
        allowed_categories = ('LC', 'Ll', 'Lu', 'Lo', 'Lu')
        # All the fun characters start at 1580 (hehe):
        big_list = list(map(chr, range(1580, HIGHEST_UNICODE)))
        max_chars = 1000 # Ought to be enough for anybody :)
        combined = []
        rtl_categories = ('AL', 'R') # AL == Arabic, R == Any right-to-left
        last_orientation = 'L'       # L = Any left-to-right
        # Find a good mix of left-to-right and right-to-left characters
        while len(combined) < max_chars:
            char = choice(big_list)
            if unicodedata.category(char) in allowed_categories:
                orientation = unicodedata.bidirectional(char)
                if last_orientation in rtl_categories:
                    if orientation not in rtl_categories:
                        combined.append(char)
                else:
                    if orientation in rtl_categories:
                        combined.append(char)
                last_orientation = orientation
    else:
        combined = lowercase + uppercase
    shuffle(combined) # Randomize it all to keep things interesting

数据源有了,那按照什么顺序输出呢?

这就用到了permutations 函数,生成迭代器,对数据进行排列组合然后输出。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for perm in permutations(combined, identifier_length):
            perm = "".join(perm)
            if perm not in RESERVED_WORDS: # Can't replace reserved words
                yield perm

总结

pyminifier 算是一个不错的入门项目,帮助大家学习脚本混淆,但是不要用在生产环境中,bug挺多,而且混淆能力并不是很强。接下来我会接着讲解脚本混淆的技术手段,不限于python。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-10-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 七夜安全博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
php如何将pdf为图片(PNG)
开发过程中总会遇到pdf预览的问题,下面是其中一个解决方案 无论是转化为多张还是单张图片,都需要安装PHP的Imagick扩展。可以根据下面的代码进行优化,比如自定义分辨率,自动检测文件目录,进行压缩等 /** * 将pdf文件转化为多张png图片 * @param string $pdf pdf所在路径 (/www/pdf/test.pdf pdf所在的绝对路径) * @param string $path 新生成图片所在路径 (/www/images/) * * @return array|
美团骑手
2021/12/24
1.3K0
PHP ImageMagick扩展有哪些函数?PHP ImageMagick扩展的使用方法
ImageMagick是一个免费的创建、编辑、合成图片的软件。它可以读取、转换、写入多种格式的图片。图片切割、颜色替换、各种效果的应用,图片的旋转、组合,文本,直线,多边形,椭圆,曲线,附加到图片伸展旋转。
房东的狗丶
2023/02/17
2.1K0
PHP ImageMagick扩展有哪些函数?PHP ImageMagick扩展的使用方法
PHP实现PDF转换成图片
ImageMagick 是一个图象处理软件,也可以作为PHP的一个扩展来使用。它可以编辑、显示包括JPEG、TIFF、PNM、PNG、GIF和Photo CS在内的绝大多数当今最流行的图象格式。你可以改变图象尺寸、旋转、锐化、减少颜色或加入特殊效果到图象里,并且能够以另一种图象格式保存。
用户8851537
2021/08/19
3.2K0
通过 imagick 让 PHP 生成 PSD 文件缩略图
第一步、安装ImageMagick   首先需要安装 ImageMagick ,因为 imagick 是一个可以供 PHP 调用 ImageMagick 功能的PHP扩展。(目前最新版本是:ImageMagick-6.8.9-5-Q16-x64-dll.exe)   安装目录不能有空格,我个人是安装在 C 盘根目录: C:\ImageMagick   一路默认安装即可,安装完毕后打开 CMD 命令行界面,输入:convert ,并按回车,如果能看到一大堆的内容则表示安装成功。   如果提示“ conve
胡尐睿丶
2018/01/11
3.1K0
通过 imagick 让 PHP 生成 PSD 文件缩略图
使用ImageMagick操作gif图
上篇文章我们已经学习了 GraphicsMagick 中的许多函数,也说过 GraphicsMagick 是 ImageMagick 的一个分支,所以他们很多的函数都是一样的使用方式和效果,相似的内容我们也就不再多说了,感兴趣的朋友可以直接查阅官方文档。
硬核项目经理
2021/09/02
1.7K0
基于 PHP 实现的微信小程序 pdf 文件的预览服务
前段时间文库类微信小程序开发中遇到个问题,就是要在小程序中预览阿里云 OSS 中的 pdf 文件。微信官方给的方案就一个,就是把文档缓存到本地然后用资源管理器打开。
PHP开发工程师
2022/05/25
2.1K0
基于 PHP 实现的微信小程序 pdf 文件的预览服务
Python将PDF转成图片PNG和JPG
前言:在最近的测试中遇到一个与PDF相关的测试需求,其中有一个过程是将PDF转换成图片,然后对图片进行测试。
软测小生
2019/08/06
15.7K0
Python将PDF转成图片PNG和JPG
php中网页生成图片的方式,类似长微博图片生成器「建议收藏」
导读:因媒体站微博传播需要,需在转发文章至新浪微博时能将文章正文已图片形式传播出去,用以提高微博内容转发积极性,顾需要在原有php项目代码中加入网页转图片功能。
全栈程序员站长
2022/08/31
2.3K0
imagick 操作 pdf 生成首页(某页)缩略图 + 总页数
在测试阶段中,发现由于pdf首页分辨率过大导致上传失败,故需要先使用pingImage来验证:
躺平程序员老修
2023/09/05
4220
imagick 操作 pdf 生成首页(某页)缩略图 + 总页数
Python——批量将PDF文件转为图片
思索
2024/08/15
2340
Python——将PPT和Word转为PDF文件
思索
2024/08/15
2540
Imagemagick邂逅Getimagesize的那点事儿
前段时间写的文章,在微博上说7月底结束分享一下,总算可以发了。感谢 @voidfyoo 提出的这个问题。
FB客服
2019/08/02
1.1K0
Imagemagick邂逅Getimagesize的那点事儿
Python将PDF转成图片—PyMuPDF和pdf2image
前言:在最近的测试中遇到一个与PDF相关的测试需求,其中有一个过程是将PDF转换成图片,然后对图片进行测试。
软测小生
2019/08/06
3K0
Python将PDF转成图片—PyMuPDF和pdf2image
使用Python将PDF转换成图片
    必须在Linux环境下,使用到的环境和工具:CentOS7+Python3.6+pdf2image+poppler
py3study
2020/01/07
3.7K0
python pdf 转 image
最近项目需要pdf中提取内容,pdf是扫描版,想通过转成图片,通过图像识别区分出段落,然后进行ocr识别,得到结构化数据
vell001
2018/10/29
5.1K0
python pdf 转 image
imagemagick convert pdf转图片时遇到找不到gswin64c.exe的问题(多装一个octave解决)
imagemagick是强大且免费的命令行图片批量处理工具(尤其是pdf图片互相转换),常用的是它的经典convert命令(imagemagick.org->download
Kitov
2022/04/13
2.7K1
imagemagick convert pdf转图片时遇到找不到gswin64c.exe的问题(多装一个octave解决)
CVE-2022-44268 ImageMagick任意文件读取漏洞
我平时基本不单独发一些漏洞复现的文章,除非觉得很有学习意义。ImageMagick这个属于特例,因为还是蛮有影响的,包括我司的许多产品实际上都是使用ImageMagick作为底层能力,之前有出现过因为Ghostscript的RCE 0day导致使用了ImageMagick的业务可以被RCE,每次出现新漏洞都要紧急排查和修复一波。
Y1ng
2023/03/08
2.3K0
CVE-2022-44268 ImageMagick任意文件读取漏洞
pdf2image类库实现批量pdf转图片
通过pdf2image来实现对PDF文件的处理工作,我们本次主要做的是将PDF文件批量转成图片。之前写过批量提取封面的文章,传送:Python提取PDF第一页为封面图片【批量提取】,但是在后期的深入编写过程中遇到一些问题,近期再次深入编写程序,一起来看看代码吧!
申霖
2020/10/27
3.7K0
pdf2image类库实现批量pdf转图片
用Python实现PDF与图片的相互转换
大家好,我是朱小五。今天分享两个小案例,用Python将一堆图片转成Pdf文档,以及将Pdf文档转成一堆图片(或者称之为提取PDF中的图片)。
快学Python
2023/02/10
1.3K0
用Python实现PDF与图片的相互转换
零代码编程:用Kimichat从PDF文件中批量提取图片
你是一个Python编程专家,要完成一个网页爬取Python脚本的任务,具体步骤如下:
AIGC部落
2024/06/24
3500
零代码编程:用Kimichat从PDF文件中批量提取图片
相关推荐
php如何将pdf为图片(PNG)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档