在C中搜索和编辑值在当前过程的堆中

发布于 2025-01-30 01:18:28 字数 1463 浏览 1 评论 0原文

因此,在我们的大学作业中,我们被要求更改两个顺序printf(“%s”,s1)的输出; printf(“%s”,s2);函数而无需触摸变量。目的是让我们在基于Linux的系统上使用该过程的内存布局的理论知识。

预期输出是针对第一个printf调用以按空格拆分的S1和S2,以及第二次输出,以按原始应用程序预期保留。已知s1s2的值和大小。

我最初的想法是malloc(0),并减去等于字符串长度的偏移量(块尺寸值+1),然后将其施放为char *。由于2个字符串值很小(绝对小于4KIB,这是页面大小),所以我希望只有一个分配给堆的区域,因此是线性的。

但是从看来我得到的值零值,这意味着我正在查看未命令的内存,或者我希望找到的字符串与众不同。

以下是所讨论的代码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void heap_attack() { 
    // alternatively it can have signature of 
    // void heap_attack(void * v);
    // but the task is assumed to be solvable with the original signature
    
}

int main(int argc, char const *argv[])
{
    char * s1 = malloc(9);
    char * s2 = malloc(9);

    if (s1 == NULL || s2 == NULL) return EXIT_FAILURE;

    strcpy(s1, "s0000000");
    strcpy(s2, "s1111111");

    heap_attack();

    printf("student 1: %s\n", s1);
    printf("student 2: %s\n", s2);

    free(s1);
    free(s2);

    return 0;
}

我对HEAP_ATTACK的实现开始如下:

void heap_attack() {
  char * heap_end = malloc(0) - 1; // 1 for the size fragment preceding writable space
  char * s1 = heap_end - 9;
  printf("%s", s1); // here i expected to see the s1111111 string printed to stdout
}

So in our university assignment we were asked to change the output of two sequential printf("%s", s1); printf("%s", s2); functions without touching the variables. The intent was for us to use the theoretical knowledge of the memory layout of the process on Linux based systems.

The expected output is for the first printf call to output both s1 and s2 split by space(s), and for the output of the second to remain as intended by the original application. The values and sizes of s1, and s2 are known.

My initial idea was to malloc(0) and subtract the offset equal to the length of the string (+1 for the chunk size value) , and then cast that as a char *. Since the 2 string values are very small (definitely less than 4KiB, which is the page size) I was hoping that there'd be just one region allocated for heap, and hence it is linear.

But from what it seems I get values of zero, which means I'm looking through an un-initialized memory, or something different then the strings I hoped to locate.

Below is the code in question:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void heap_attack() { 
    // alternatively it can have signature of 
    // void heap_attack(void * v);
    // but the task is assumed to be solvable with the original signature
    
}

int main(int argc, char const *argv[])
{
    char * s1 = malloc(9);
    char * s2 = malloc(9);

    if (s1 == NULL || s2 == NULL) return EXIT_FAILURE;

    strcpy(s1, "s0000000");
    strcpy(s2, "s1111111");

    heap_attack();

    printf("student 1: %s\n", s1);
    printf("student 2: %s\n", s2);

    free(s1);
    free(s2);

    return 0;
}

My implementation of the heap_attack begins as follows:

void heap_attack() {
  char * heap_end = malloc(0) - 1; // 1 for the size fragment preceding writable space
  char * s1 = heap_end - 9;
  printf("%s", s1); // here i expected to see the s1111111 string printed to stdout
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

怀里藏娇 2025-02-06 01:18:28

假设您是使用GLIBC(最常见的设置)从事GNU/Linux的工作,那么您可以做出一些假设可以帮助您解决问题。

  1. 正如您所说,两个分配的块将居住在相同的新初始化(线性)堆中,通常覆盖多个页面(几个KBS)。仅供参考:Linux X86上的页面大小为4K,而不是4m。
  2. 在堆的初始化之后,连续分配(malloc()呼叫没有任何free(Free()在中间)将分配内存的连续块,因此第一个分配的字符串将会就在第二个之前。
  3. 您可以通过查看“ nofollow noreferrer”>在源代码上(选择正确的版本,运行/lib/x86_64-linux-gnu/libc.so.6将打印版本)。您也可以查看我的其他答案我简要地解释了malloc_chunk 。
  4. 通过查看源代码或测试,您可以注意到Malloc'd块实际上是将大小舍入到2 * size_t的倍数上。

假设1和2(我们可以在此特定环境中再次做出)保证:

  • s2&gt; s1(即s2s1之后的内存中)
  • 应完全(S2 -S1 -S1 -Strlen(S2)-1 在两个字符串之间的字节,除非strlen(s2)更改
  • 下一个分配malloc(x), 否则此值不会更改。 /code>,并且始终在s2的相同固定偏移量中,您可以轻松计算一次(假设s2保持相同的长度)

。帮助您找出所需的计算块的实际尺寸。 > sizeof(size_t)== 8 )。 /a>将为您提供确切的大小,不包括标题

。后来尝试释放(损坏的)块很可能会导致崩溃。在您的情况下,您可以完全避免free()完全不需要它。无论如何,操作系统都会在程序终止上回收内存。

您的heap_attack()的可能实现是:

void heap_attack(void) {
    char *top_chunk = malloc(1);
    char *top_chunk_header = top_chunk - 2 * sizeof(size_t);
    char *s2 = top_chunk_header - 16;       // assuming strlen(s2) <= 15
    char *s1 = s2 - 2 * sizeof(size_t) - 16 // assuming strlen(s1) <= 15;

    // Fill memory between s1 + 8 and s2 with spaces
}

Assuming that you are working on GNU/Linux using glibc, which is the most common setup, then you can make some assumptions that will help you solve the problem.

  1. As you say, both allocated chunks will reside into the same newly initialized (linear) heap, which usually spans multiple pages (several KBs). FYI: page size on Linux x86 is 4K, not 4M.
  2. Right after initialization of the heap, consecutive allocations (malloc() calls without any free() in the middle) will allocate contiguous chunks of memory, so the first allocated string will be right before the second.
  3. You can know the structure used by the glibc allocator by looking at the source code (pick the correct version, running /lib/x86_64-linux-gnu/libc.so.6 will print the version). You can also look at this other answer of mine where I briefly explain the internal layout of a malloc_chunk.
  4. Either by looking at the source code or by testing, you can notice that malloc'd chunks are actually rounded up in size to multiples of 2 * size_t.

Assumptions 1 and 2 (which again we can make in this specific environment) guarantee that:

  • s2 > s1 (that is, s2 is in memory after s1)
  • There should be exactly (s2 - s1 - strlen(s2) - 1 bytes between the two strings, and this value will not change unless strlen(s2) changes.
  • The next allocation malloc(x) will be after s2, and always at the same fixed offset from s2, which you can easily calculate once and then use (assuming s2 keeps the same length).

Assumption 3 above will help you figure out the actual size of the chunks for the calculations you need. For malloc(9) the corresponding chunk (header included) would be 32 bytes (16 for header + 16 for data assuming sizeof(size_t) == 8). Furthermore malloc_usable_size() will give you the exact size excluding the header.

Filling up those bytes with spaces will accomplish what you wish for. However, in doing so, you will destroy the chunk header for s1, and any later attempt at freeing the (corrupted) chunk will most likely cause a crash. You can avoid free() altogether in your case since you don't really need it. The operating system will reclaim memory anyway on program termination.

A possible implementation of your heap_attack() would be:

void heap_attack(void) {
    char *top_chunk = malloc(1);
    char *top_chunk_header = top_chunk - 2 * sizeof(size_t);
    char *s2 = top_chunk_header - 16;       // assuming strlen(s2) <= 15
    char *s1 = s2 - 2 * sizeof(size_t) - 16 // assuming strlen(s1) <= 15;

    // Fill memory between s1 + 8 and s2 with spaces
}
瞄了个咪的 2025-02-06 01:18:28
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#define STRING_DISTANCE         (0x20)
#define ARBITRARY_STACK_OFFSET  (20)

// The strategy is as follows: We can tell the difference from the contigous heap blocks (0x20) in advance (at least for the same machine)
// So given s1 - we would like to simply overwrite everything between with spaces - that way when it prints s1, it will print spaces until s2 and its null terminator
// The only challenge is to find s1, the way we do that here is by simply traveling up the stack and finding our two strings, assuming we know their offsets.
void heap_attack()
{ 
    size_t a = 0;
    void * s1 = 0;

    for (uintptr_t * stack_ptr = &a; a < ARBITRARY_STACK_OFFSET; a += 1)    // Travel up the stack, from a variable in our frame, to the function calling us.
    {
        if (stack_ptr[a] - (uintptr_t)s1 == STRING_DISTANCE)
        {
            printf("stack offset - %lu\ns1 - %p\n", a, (void *)stack_ptr[a]);
            break;
        }

        s1 = stack_ptr[a];
    }

    for (char * x = (char *)s1 + strlen(s1); x < s1 + STRING_DISTANCE; x += 1)
    {
        *x = ' ';
    }
}

int main()
{
    char * s1 = malloc(9);
    char * s2 = malloc(9);

    printf("%p - %p\n", s1, s2);

    if (s1 == NULL || s2 == NULL) return EXIT_FAILURE;

    strcpy(s1, "s0000000");
    strcpy(s2, "s1111111");

    heap_attack();

    printf("student 1: %s\n", s1);
    printf("student 2: %s\n", s2);

    // I disabled the frees because I corrupted the blocks, corrupting the blocks is neccessary so it would print spaces between them
    // If we don't want to corrupt the blocks, another option would be to also override the format string, but that's outside the scope of this challenge imo
    // free(s1);
    // free(s2);


    return 0;
}

如果我们选择堆解决方案:

void heap_attack()
{ 
    char * s1 = (char *)malloc(9) - STRING_DISTANCE * 2;

    for (char * x = (char *)s1 + strlen(s1); x < s1 + STRING_DISTANCE; x += 1)
    {
        *x = ' ';
    }
}
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#define STRING_DISTANCE         (0x20)
#define ARBITRARY_STACK_OFFSET  (20)

// The strategy is as follows: We can tell the difference from the contigous heap blocks (0x20) in advance (at least for the same machine)
// So given s1 - we would like to simply overwrite everything between with spaces - that way when it prints s1, it will print spaces until s2 and its null terminator
// The only challenge is to find s1, the way we do that here is by simply traveling up the stack and finding our two strings, assuming we know their offsets.
void heap_attack()
{ 
    size_t a = 0;
    void * s1 = 0;

    for (uintptr_t * stack_ptr = &a; a < ARBITRARY_STACK_OFFSET; a += 1)    // Travel up the stack, from a variable in our frame, to the function calling us.
    {
        if (stack_ptr[a] - (uintptr_t)s1 == STRING_DISTANCE)
        {
            printf("stack offset - %lu\ns1 - %p\n", a, (void *)stack_ptr[a]);
            break;
        }

        s1 = stack_ptr[a];
    }

    for (char * x = (char *)s1 + strlen(s1); x < s1 + STRING_DISTANCE; x += 1)
    {
        *x = ' ';
    }
}

int main()
{
    char * s1 = malloc(9);
    char * s2 = malloc(9);

    printf("%p - %p\n", s1, s2);

    if (s1 == NULL || s2 == NULL) return EXIT_FAILURE;

    strcpy(s1, "s0000000");
    strcpy(s2, "s1111111");

    heap_attack();

    printf("student 1: %s\n", s1);
    printf("student 2: %s\n", s2);

    // I disabled the frees because I corrupted the blocks, corrupting the blocks is neccessary so it would print spaces between them
    // If we don't want to corrupt the blocks, another option would be to also override the format string, but that's outside the scope of this challenge imo
    // free(s1);
    // free(s2);


    return 0;
}

And if we choose the heap solution:

void heap_attack()
{ 
    char * s1 = (char *)malloc(9) - STRING_DISTANCE * 2;

    for (char * x = (char *)s1 + strlen(s1); x < s1 + STRING_DISTANCE; x += 1)
    {
        *x = ' ';
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文