SQLMap 源码阅读笔记01

0x00 前言

SQLMap作为SQL注入的神器,又方便同时功能也非常的多,所以阅读sqlmap能学习到很多东西,这篇文章作为开篇来学习一下,也算是一个系列的开始

0x01 正文

我们这里直接从入口文件 sqlmap.py 开始看起来

__import__ 相当于动态引入类,和java反射有些类似,这里看到代码中动态引入lib.utils.versioncheck库,我们跟过去看看

    try:
        # 动态引入sqlmap对版本检查文件
        __import__("lib.utils.versioncheck")  # this has to be the first non-standard import
    except ImportError:
        sys.exit("[!] wrong installation detected (missing modules). Visit 'https://github.com/sqlmapproject/sqlmap/#installation' for further details")

versioncheck文件

首先进行了一个语言版本的检测,如果语言版本低于2.6那么就会自动退出程序

接下来的extensions = ("bz2", "gzip", "pyexpat", "ssl", "sqlite3", "zlib") 中存的是运行sqlmap必要的库

这里还是利用__import__ 进行一个动态引入,如果没有安装库那么自然就会进行一个报错,然后被try...except 进行一个捕捉添加到我们专门存储报错信息的errors数组中

所以总结一下我们可以发现,这个文件主要是负责python版本的检测 以及运行过程中必要的库的一些检测

# 如果低于 2.6 程序自动退出
if PYVERSION < "2.6":
    sys.exit("[%s] [CRITICAL] incompatible Python version detected ('%s'). To successfully run sqlmap you'll have to use version 2.6, 2.7 or 3.x (visit 'https://www.python.org/downloads/')" % (time.strftime("%X"), PYVERSION))

errors = []
# 集合中存放着sqlmap需要的库,然后进行动态引入 如果报错那么就添加错误信息
# 这个功能主要是检查必要的库是否存在
extensions = ("bz2", "gzip", "pyexpat", "ssl", "sqlite3", "zlib")
for _ in extensions:
    try:
        __import__(_)
    except ImportError:
        errors.append(_)

if errors:
    errMsg = "[%s] [CRITICAL] missing one or more core extensions (%s) " % (time.strftime("%X"), ", ".join("'%s'" % _ for _ in errors))
    errMsg += "most likely because current version of Python has been "
    errMsg += "built without appropriate dev packages"
    sys.exit(errMsg)

我们还是继续查看我们的主文件 sqlmap.py

这一段就是捕捉前面的报错信息,如果前面出现了报错这里就会进行一个捕捉

首先会检测我们当前的命名空间中是否存在logger(个人觉得通俗的说就是检测有没有引入logger库),如果存在的话就将错误信息写到我们的日志中,并且记录危害为严重级别

如果没有就直接进行退出

except KeyboardInterrupt:
    # 用户自行终止
    errMsg = "user aborted"

    #  如果命名空间中引入 logger就将错误信息写到我们的日志中
    if "logger" in globals():
        # 在日志中记载 critical 级别的信息
        logger.critical(errMsg)
        raise SystemExit
    else:
        import time
        sys.exit("\r[%s] [CRITICAL] %s" % (time.strftime("%X"), errMsg))

继续往下看,下面是一个modelPath函数

一开始看到这个函数有点蒙蒙的我们来仔细看一下

def modulePath():
    """
    This will get us the program's directory, even if we are frozen
    using py2exe
    """
    # weAreFrozen 返回的信息如果是true 路径就为sys.executable 反之就是说明是脚本 赋值为 __file__
    # 如果是exe 返回的路径是sys.executable 反之返回文件的路径
    try:
        _ = sys.executable if weAreFrozen() else __file__
    except NameError:
        _ = inspect.getsourcefile(modulePath)

    # 将获取的路径转化成想要的编码 sys.getfilesystemencoding() 获取系统默认编码 utf-8
    return getUnicode(os.path.dirname(os.path.realpath(_)), encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)

我们看到if语句中调用了 weAreFrozen()我们跟过去看一下,发现给了一个链接我们去看看

发现主要是为了解决如下问题

image-20201107213748212

大致意思就是:如果我们将python文件打包之后,负责打包的py2exed中不包含__file__ 这就导致exe运行过程中无法使用该方法,但是可以使用 . 但是这也只代表着只能当前的应用目录下才能进行运行

所以modulePath方法就是为了解决 当被打包成exe的时候无法使用__file__的情况下 仍能获取当前执行文件路径的问题

接下来我们来看看怎么实现吧

def weAreFrozen():
    """
    Returns whether we are frozen via py2exe.
    This will affect how we find out where we are located.

    # Reference: http://www.py2exe.org/index.cgi/WhereAmI
    """
    return hasattr(sys, "frozen")

首先 hasattr 方法是检测 对象中是否包含frozen 如果包含返回true 不包含则返回 false

在脚本的情况下我们发现我们的sys中并没有这个属性

image-20201107215004634

接下来利用pyinstaller 对程序进行一个打包,我们打包成一个exe 来观察是否含有 frozen 属性

我们写一个简单的测试py文件

import sys
print(sys.executable)
print(sys.frozen)
print("hello,world")

然后利用

pyinstaller -F 1.py

然后进入 dist文件夹,并且进行执行,发现exe中果然含有frozen属性

image-20201107215237452

然后再来看这个python语句

如果 weAreFrozen 为 True 说明是exe 然后就 赋值给 _ 也就是当前文件的路径

反之说明不是exe文件则可以正常使用 __file__ 方法

 _ = sys.executable if weAreFrozen() else __file__

(不得不说,代码写的真的太好了,看湿了

点赞

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像