如何在C中的虚拟内存中解密文件

时间:2018-08-23 13:44:37

标签: encryption c virtual-memory

我正在尝试解密内存中的文件,并且此文件已使用openssl加密。 为此,我使用mmap将加密文件加载到内存中,如下所示:

void* src = mmap(0, statbuf.st_size,PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

并复制它,因为我不想修改我的原始文件

void* dst = mmap(0, statbuf.st_size,PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
memcpy (dst, src, statbuf.st_size);

在此步骤中一切正常,但我不知道下一步该怎么做。 最初出于测试目的,我使用openssl命令加密文件:

system("openssl enc -aes-256-cbc -salt -in my_encryptedfile -out my_encryptedfile.enc -pass")

并使用以下命令将其解密:

system("openssl enc -d -aes-256-cbc -in my_encryptedfile.enc -out my_encryptedfile -pass pass:")

但是在这种情况下我无法使用dst,因此我搜索并发现了EVP对称加密和解密。 link here

然后我使用该代码github code加密和解密我的文件

我尝试使用Key和IV以及内存中的解密,它似乎可以正常工作,但是我有一个我不明白的问题。当我转储解密文件的缓冲区时,我在文件末尾看到“ SPACES / NULS”,但我不知道为什么它会显示出来。当我尝试通过调用此函数在内存中执行我的binany时:

  

func()

我遇到了细分错误

有任何线索吗?

typedef void (*JittedFunc)(void);

void* alloc_writable_memory(void *ptr, size_t size) {
   ptr = mmap(0, size,
                   PROT_READ | PROT_WRITE,
                   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  if (ptr == (void*)-1) {
    perror("mmap");
    return NULL;
  }
  return ptr;
}

int make_memory_executable(void* m, size_t size) {
  if (mprotect(m, size, PROT_READ |PROT_WRITE | PROT_EXEC) == -1) {
    perror("mprotect");
    return -1;
  }
  return 0;
}

int do_crypt(char *in, char *out, int do_encrypt, int inlen)
{
  /* Allow enough space in output buffer for additional block */
  unsigned char  outbuf[inlen + EVP_MAX_BLOCK_LENGTH];
  int outlen;
  EVP_CIPHER_CTX *ctx;
  /* Bogus key and IV: we'd normally set these from
  * another source.
  */
  unsigned char key[] = "0123456789abcdeF";
  unsigned char iv[] = "1234567887654321";
  //int n;
printf("step1\n");
  /* Don't set key or IV right away; we want to check lengths */
  ctx = EVP_CIPHER_CTX_new();
  printf("step2\n");
  EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, NULL, NULL,do_encrypt);
  printf("step3\n");
  OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
  OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 16);

  /* Now we can set key and IV */
  EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, do_encrypt);
  printf("step4\n");
      if(!EVP_CipherUpdate(ctx, outbuf,&outlen, in, inlen))
        {
          printf("test 2.1: %d %d\n", inlen, outlen);
          printf("step8\n");
          /* Error */
          EVP_CIPHER_CTX_free(ctx);
          return 0;
        }

    //BIO_dump_fp (stdout, (const char *)outbuf, outlen);
    printf(" test 2: %d %d\n", inlen, outlen);

  if(!EVP_CipherFinal_ex(ctx, outbuf, &outlen))
    {
      printf("step11\n");

    EVP_CIPHER_CTX_free(ctx);
    return 0;
    }
//copy the decryted buffer in another memory space
    memcpy(out, outbuf, outlen);
    printf(" test 3: %d %d\n", inlen, outlen);
    //BIO_dump_fp (stdout, (const char *)outbuf, outlen);
    printf("step12\n");
    //fwrite(outbuf, 1, outlen, out);
    printf("step13\n");
    EVP_CIPHER_CTX_free(ctx);
    return 1;
}

int main()
{
  FILE *src, *dst;
  char *src_mem, *dst_mem, *dst2_mem = NULL;
  struct stat statbuf;
  int fd;

  src = fopen("hello_encrypted", "rb");
  if (!src) {
      /* Unable to open file for reading */
      fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
      return errno;
  }
  /*get the file des from a file*/
  fd = fileno(src);

  /* find size of input file */
  if (fstat (fd,&statbuf) < 0)
    {printf ("fstat error");
     return 0;
    }

  /* go to the location corresponding to the last byte */
  if (lseek (fd, statbuf.st_size - 1, SEEK_SET) == -1)
    {printf ("lseek error");
     return 0;
    }
  if ((src_mem = mmap (0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0)) == (caddr_t) -1)
      {
        printf ("mmap error for input");
        return 0;
      }
  if ((dst_mem = mmap (0,  statbuf.st_size, PROT_READ | PROT_WRITE,
    MAP_SHARED | MAP_ANONYMOUS , -1, 0)) == (caddr_t) -1)
    {
      printf ("mmap error for output");
      return 0;
    }

    if ((dst2_mem = mmap (0,  statbuf.st_size , PROT_READ | PROT_WRITE,
      MAP_SHARED | MAP_ANONYMOUS , -1, 0)) == (caddr_t) -1)
      {
        printf ("mmap error for output");
        return 0;
      }
    memcpy(dst_mem, src_mem, statbuf.st_size);

    int n;
    /* 0 for decrypting or 1 for encrypting*/
    n = do_crypt(dst_mem,dst2_mem, 0, statbuf.st_size);
    printf("%d\n", n);
    make_memory_executable(dst2_mem, statbuf.st_size);
//dump of the decrypt binary
    BIO_dump_fp (stdout, (const char *)dst2_mem, statbuf.st_size);

//try to launch the decrypted binary ==> segmentation fault
   JittedFunc func = dst2_mem;
func();
  fclose(src);
  return 0;
}

1 个答案:

答案 0 :(得分:0)

我会从第一个mmap中删除标志PROT_WRITE,因为您不想修改原始文件,我想您也可以使用PROT_PRIV,但请看一下mmap的含义。

另一方面,要解密缓冲区,您可以使用许多库(其中很多基于openssl),我特别喜欢CryptoPP,但还有许多其他库。这是一个示例,说明您的代码在CryptoPP上的外观

try {
    // CryptoPP::ECB_Mode< CryptoPP::AES >::Decryption d;
    // CrypoPP::CBC_Mode< CryptoPP::AES >::Decryption d;
    CrypoPP::CBC_CTS_Mode< CryptoPP::AES >::Decryption d;
    // What ever mode is best for you

    d.SetKey(key.data(), key.size());

    // The StreamTransformationFilter removes
    //  padding as required.
    CryptoPP::StringSource s((const uint8_t*)dst, length_dst, true,
            new CryptoPP::StreamTransformationFilter(d,
                    new CryptoPP::StringSink(recovered)
            ) // StreamTransformationFilter
    ); // StringSource
} catch(const CryptoPP::Exception& e) {
    std::cout << "ERROR decrypting:" << e.what() << std::endl;
    return;
}