GAS(AT&T)汇编中修改某地址值后另一地址值异常变化的原因
汇编函数
ints_to_ascii数据篡改问题分析 问题描述
- 函数功能:接收一组(x,y)坐标数组(每个数是0-32767范围内的无符号整数),转换为ASCII格式
"x \t y \n"并存入目标缓冲区,从坐标数组末尾反向处理至起始,仅处理最后一组数据时出现异常。 - 测试输入(十进制):
2084, 3146, 30093, 9127 - 异常现象:加载4个16位无符号整数后,通过GDB确认
%rdi指向的第一个数初始值为2084;但执行movb $10, (%rcx) # insert newline语句后,%rdi指向的地址值发生了意外篡改,已通过多次插入movq (%rdi), %r12 # test to see what is stored at (%rdi)定位到该语句为数据变化的触发点。
函数代码
.section .text .globl ints_to_ascii # void ints_to_ascii() # %rdi = Array start address # %rsi = Data length # %rdx = print buffer address # %rcx = print buffer length ints_to_ascii: push %rbp movq %rsp, %rbp addq %rdi, %rsi # make rsi point at end of coordinate array, used to get 8 byte numbers addq %rdx, %rcx # make rcx point at end of buffer movq $10, %r10 # Divisor (10 for decimal) .LparseData_coordinateLoop: cmpq %rdi, %rsi jle .LparseData_coordinateLoop_end dec %rcx # Move the pointer one position to the left movq (%rdi), %r12 # test to see what is stored at (%rdi) movb $10, (%rcx) # insert newline movq (%rdi), %r12 # test to see what is stored at (%rdi) subq $8, %rsi # point to the next place for a number movq (%rsi), %rax convert_y_loop: xorq %rdx, %rdx # Clear the remainder divq %r10 # Divide RAX by 10, result in RAX, remainder in RDX dec %rcx # Move the pointer one position to the left mov %dl, (%rcx) # Store the ASCII digit in the buffer addq $48, (%rcx) #add 48 to convert to ascii cmpq $0, %rax # Check if quotient is zero jne convert_y_loop # If not zero, continue the loop convert_y_loop_end: dec %rcx # Move the pointer one position to the left movb $9, (%rcx) # insert tab subq $8, %rsi # point to the next place for a number movq (%rsi), %rax convert_x_loop: xorq %rdx, %rdx # Clear the remainder divq %r10 # Divide RAX by 10, result in RAX, remainder in RDX dec %rcx # Move the pointer one position to the left mov %dl, (%rcx) # Store the ASCII character addq $48, (%rcx) #add 48 to convert to ascii cmpq $0, %rax # Check if quotient is zero jne convert_x_loop # If not zero, continue the loop convert_x_loop_end: jmp .LparseData_coordinateLoop .LparseData_coordinateLoop_end: movq %rbp, %rsp pop %rbp ret
问题根源
- 缓冲区越界写入:函数中
%rcx初始指向缓冲区末尾,每次通过dec %rcx往回写入字符,但未做边界检查。当处理最后一组坐标时,%rcx会越过缓冲区起始地址%rdx,写到输入数组的内存区域(即%rdi指向的地址),导致movb $10, (%rcx)直接篡改了输入数组的数据。 - 数据步长与内存布局错误:输入的每个坐标是16位(2字节)无符号整数,但函数中错误地按8字节(64位)处理(
subq $8, %rsi),同时初始计算数组末尾的逻辑addq %rdi, %rsi完全错误——%rsi是元素个数,正确的数组末尾地址应为%rdi + (%rsi * 2),原逻辑直接将元素个数加到起始地址上,导致指针定位完全混乱,进一步加剧了越界问题。
修复建议
- 修正内存指针计算:
- 数组末尾地址计算:将
addq %rdi, %rsi改为lea (%rdi, %rsi, 2), %rsi(每个元素2字节,元素个数为%rsi)。 - 指针移动步长:将两处
subq $8, %rsi改为subq $2, %rsi,匹配16位整数的内存宽度。
- 数组末尾地址计算:将
- 增加缓冲区边界检查:每次
dec %rcx后,添加cmpq %rdx, %rcx,若jl(小于起始地址)则终止处理,避免越界写。 - 调整循环终止条件:原循环
cmpq %rdi, %rsi需结合修正后的步长,确保循环处理完所有(x,y)组。
内容的提问来源于stack exchange,提问作者Gusbc
相关产品推荐
相关产品推荐

