加密系统文件时程序崩溃
program crashes when encrypting system files
我写了这段代码来加密和解密文件夹的内容,这两个功能在加密普通文件时都很好用,但是当我将文件夹更改为系统文件夹时,程序崩溃了,当我在崩溃前检查最新文件时,我没有能够打开其中一些(文件在另一个程序中打开),其中一些我无法进行更改。
我正在处理我认为的所有错误,但是当它到达另一个程序打开的文件时它仍然会崩溃,如何解决这个问题以忽略这些类型的文件并继续而不是崩溃?
我认为结构对 post 并不重要。
char ListFiles(const wchar_t* folder, CIPHER* conf)
{
wchar_t wildcard[MAX_PATH + 1];
swprintf(wildcard, sizeof(wildcard) / sizeof(*wildcard), L"%s\*", folder);
WIN32_FIND_DATAW fd;
HANDLE handle = FindFirstFileW(wildcard, &fd);
if (handle == INVALID_HANDLE_VALUE) return 1;
do
{
if (wcscmp(fd.cFileName, L".") == 0 || wcscmp(fd.cFileName, L"..") == 0)
continue;
wchar_t path[MAX_PATH + 1];
swprintf(path, sizeof(path) / sizeof(*path), L"%s\%s", folder, fd.cFileName);
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !(fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))
ListFiles(path, &conf);
if (fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE && !(fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))
{
wprintf(L"%s\n", path);
FILE* f_dec;
FILE* f_input = _wfopen(path, L"rb");
FILE* f_enc = _wfopen(wcscat(path, L".encrypted"), L"wb");
if (!f_input || !f_enc) {
fprintf(stderr, "fopen error: %s\n", strerror(errno));
continue;
}
conf->encrypt = 1; // encryption
if (AES_L(conf, f_input, f_enc) != 0)
continue;
f_enc = _wfopen(path, L"rb");
f_dec = _wfopen(wcscat(path, L".decrypted"), L"wb");
if (!f_dec || !f_enc) {
fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
continue;
}
conf->encrypt = 0; // decryption
if (AES_L(conf, f_enc, f_dec) != 0)
continue;
puts("\n\n");
}
} while (FindNextFileW(handle, &fd));
FindClose(handle);
return 0;
}
char AES_L(CIPHER* params, FILE* ifp, FILE* ofp)
{
unsigned int inlen, outlen;
unsigned char* inbuf = (unsigned char*)malloc(params->bufsize);
unsigned char* outbuf = (unsigned char*)malloc(params->bufsize + EVP_MAX_BLOCK_LENGTH);
if (inbuf == NULL || outbuf == NULL)
{
printf("memory cannot be allocated\n");
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
EVP_CIPHER_CTX* ctx;
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
fprintf(stderr, "ERROR: EVP_CIPHER_CTX_new failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
if (!EVP_CipherInit_ex(ctx, params->cipher_type, NULL, params->key, params->iv, params->encrypt)) {
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
while (1) {
// Read in data in blocks until EOF. Update the ciphering with each read.
inlen = fread(inbuf, sizeof(*inbuf), params->bufsize, ifp);
if (ferror(ifp)) {
fprintf(stderr, "ERROR: fread error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf, errno);
return 1;
}
if (!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)) {
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
fwrite(outbuf, sizeof(*outbuf), outlen, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf, errno);
return 1;
}
if (inlen < params->bufsize) /* Reached End of file */
break;
}
/* Now cipher the final block and write it out to file */
if (!EVP_CipherFinal_ex(ctx, outbuf, &outlen)) {
fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
fwrite(outbuf, sizeof(*outbuf), outlen, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 0;
}
更新:
void cleanup(FILE* ifp, FILE* ofp, unsigned char* inputBuf, unsigned char* outputBuf)
{
free(inputBuf);
free(outputBuf);
fclose(ifp);
fclose(ofp);
}
typedef struct {
unsigned int key_size;
unsigned int block_size;
unsigned int bufsize;
unsigned char* key;
unsigned char* iv;
unsigned int encrypt;
const EVP_CIPHER* cipher_type;
} CIPHER;
我发现您的代码存在一些问题,尽管很难知道如果没有其余代码它们是否会导致崩溃(例如,我们看不到 cleanup
方法),或者如何创建和初始化 params
.
第一个问题是您可能正在泄漏文件句柄。当您打开 ListFiles
中的文件时,您会成对打开它们,然后检查其中是否有 NULL
,如果有,则继续循环。
FILE* f_input = _wfopen(path, L"rb");
FILE* f_enc = _wfopen(wcscat(path, L".encrypted"), L"wb");
if (!f_input || !f_enc) {
fprintf(stderr, "fopen error: %s\n", strerror(errno));
continue;
}
f_input
打开正确,f_enc
打开失败怎么办?源文件将保持打开状态,直到程序结束。您应该分别检查它们中的每一个。
在AES_L
中分配内存时会出现类似的问题:
unsigned char* inbuf = (unsigned char*)malloc(params->bufsize);
unsigned char* outbuf = (unsigned char*)malloc(params->bufsize + EVP_MAX_BLOCK_LENGTH);
if (inbuf == NULL || outbuf == NULL)
{
printf("memory cannot be allocated\n");
return 1;
}
如果其中一个缓冲区(可能 inbuf
)分配正确但 outbuf
失败,您将泄漏内存,因为您没有释放正确分配的缓冲区(尽管,老实说,我认为这不是崩溃的直接问题,因为当您的内存已经很低时,就会发生这种情况。
创建加密文件和解密文件的路径时可能会出现另一个问题。 path
缓冲区的大小为 MAX_PATH+1
,对于原始文件名来说已经足够了,但是随后您执行了几个 wcscat
操作,这些操作导致将其他数据添加到路径中。如果原始文件名已经接近 MAX_PATH
限制怎么办?当您执行 wcscat
时,您将溢出堆栈中的缓冲区,这也可能导致崩溃。
最后,ListFiles
是递归的,所以如果有很多嵌套调用,你可能会 运行 出栈,这也会导致崩溃(事实上,从问题我提到我认为这是主要嫌疑人)。我会让它迭代。
无论如何,很难知道崩溃是否是由这些问题引起的,最好的选择是 运行 在调试器中。崩溃的错误消息会告诉你很多信息来确定原因。
我写了这段代码来加密和解密文件夹的内容,这两个功能在加密普通文件时都很好用,但是当我将文件夹更改为系统文件夹时,程序崩溃了,当我在崩溃前检查最新文件时,我没有能够打开其中一些(文件在另一个程序中打开),其中一些我无法进行更改。 我正在处理我认为的所有错误,但是当它到达另一个程序打开的文件时它仍然会崩溃,如何解决这个问题以忽略这些类型的文件并继续而不是崩溃? 我认为结构对 post 并不重要。
char ListFiles(const wchar_t* folder, CIPHER* conf)
{
wchar_t wildcard[MAX_PATH + 1];
swprintf(wildcard, sizeof(wildcard) / sizeof(*wildcard), L"%s\*", folder);
WIN32_FIND_DATAW fd;
HANDLE handle = FindFirstFileW(wildcard, &fd);
if (handle == INVALID_HANDLE_VALUE) return 1;
do
{
if (wcscmp(fd.cFileName, L".") == 0 || wcscmp(fd.cFileName, L"..") == 0)
continue;
wchar_t path[MAX_PATH + 1];
swprintf(path, sizeof(path) / sizeof(*path), L"%s\%s", folder, fd.cFileName);
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && !(fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))
ListFiles(path, &conf);
if (fd.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE && !(fd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM))
{
wprintf(L"%s\n", path);
FILE* f_dec;
FILE* f_input = _wfopen(path, L"rb");
FILE* f_enc = _wfopen(wcscat(path, L".encrypted"), L"wb");
if (!f_input || !f_enc) {
fprintf(stderr, "fopen error: %s\n", strerror(errno));
continue;
}
conf->encrypt = 1; // encryption
if (AES_L(conf, f_input, f_enc) != 0)
continue;
f_enc = _wfopen(path, L"rb");
f_dec = _wfopen(wcscat(path, L".decrypted"), L"wb");
if (!f_dec || !f_enc) {
fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
continue;
}
conf->encrypt = 0; // decryption
if (AES_L(conf, f_enc, f_dec) != 0)
continue;
puts("\n\n");
}
} while (FindNextFileW(handle, &fd));
FindClose(handle);
return 0;
}
char AES_L(CIPHER* params, FILE* ifp, FILE* ofp)
{
unsigned int inlen, outlen;
unsigned char* inbuf = (unsigned char*)malloc(params->bufsize);
unsigned char* outbuf = (unsigned char*)malloc(params->bufsize + EVP_MAX_BLOCK_LENGTH);
if (inbuf == NULL || outbuf == NULL)
{
printf("memory cannot be allocated\n");
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
EVP_CIPHER_CTX* ctx;
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
fprintf(stderr, "ERROR: EVP_CIPHER_CTX_new failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
if (!EVP_CipherInit_ex(ctx, params->cipher_type, NULL, params->key, params->iv, params->encrypt)) {
fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
while (1) {
// Read in data in blocks until EOF. Update the ciphering with each read.
inlen = fread(inbuf, sizeof(*inbuf), params->bufsize, ifp);
if (ferror(ifp)) {
fprintf(stderr, "ERROR: fread error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf, errno);
return 1;
}
if (!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)) {
fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
fwrite(outbuf, sizeof(*outbuf), outlen, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf, errno);
return 1;
}
if (inlen < params->bufsize) /* Reached End of file */
break;
}
/* Now cipher the final block and write it out to file */
if (!EVP_CipherFinal_ex(ctx, outbuf, &outlen)) {
fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n",
ERR_error_string(ERR_get_error(), NULL));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
fwrite(outbuf, sizeof(*outbuf), outlen, ofp);
if (ferror(ofp)) {
fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 1;
}
EVP_CIPHER_CTX_cleanup(ctx);
cleanup(ifp, ofp, inbuf, outbuf);
return 0;
}
更新:
void cleanup(FILE* ifp, FILE* ofp, unsigned char* inputBuf, unsigned char* outputBuf)
{
free(inputBuf);
free(outputBuf);
fclose(ifp);
fclose(ofp);
}
typedef struct {
unsigned int key_size;
unsigned int block_size;
unsigned int bufsize;
unsigned char* key;
unsigned char* iv;
unsigned int encrypt;
const EVP_CIPHER* cipher_type;
} CIPHER;
我发现您的代码存在一些问题,尽管很难知道如果没有其余代码它们是否会导致崩溃(例如,我们看不到 cleanup
方法),或者如何创建和初始化 params
.
第一个问题是您可能正在泄漏文件句柄。当您打开 ListFiles
中的文件时,您会成对打开它们,然后检查其中是否有 NULL
,如果有,则继续循环。
FILE* f_input = _wfopen(path, L"rb");
FILE* f_enc = _wfopen(wcscat(path, L".encrypted"), L"wb");
if (!f_input || !f_enc) {
fprintf(stderr, "fopen error: %s\n", strerror(errno));
continue;
}
f_input
打开正确,f_enc
打开失败怎么办?源文件将保持打开状态,直到程序结束。您应该分别检查它们中的每一个。
在AES_L
中分配内存时会出现类似的问题:
unsigned char* inbuf = (unsigned char*)malloc(params->bufsize);
unsigned char* outbuf = (unsigned char*)malloc(params->bufsize + EVP_MAX_BLOCK_LENGTH);
if (inbuf == NULL || outbuf == NULL)
{
printf("memory cannot be allocated\n");
return 1;
}
如果其中一个缓冲区(可能 inbuf
)分配正确但 outbuf
失败,您将泄漏内存,因为您没有释放正确分配的缓冲区(尽管,老实说,我认为这不是崩溃的直接问题,因为当您的内存已经很低时,就会发生这种情况。
创建加密文件和解密文件的路径时可能会出现另一个问题。 path
缓冲区的大小为 MAX_PATH+1
,对于原始文件名来说已经足够了,但是随后您执行了几个 wcscat
操作,这些操作导致将其他数据添加到路径中。如果原始文件名已经接近 MAX_PATH
限制怎么办?当您执行 wcscat
时,您将溢出堆栈中的缓冲区,这也可能导致崩溃。
最后,ListFiles
是递归的,所以如果有很多嵌套调用,你可能会 运行 出栈,这也会导致崩溃(事实上,从问题我提到我认为这是主要嫌疑人)。我会让它迭代。
无论如何,很难知道崩溃是否是由这些问题引起的,最好的选择是 运行 在调试器中。崩溃的错误消息会告诉你很多信息来确定原因。