2013-09-05 1 views
0

코드 버퍼를 작성하고 디스크에 직접 쓰기 수정하는 방법 :(의 WriteFile에게)

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

HANDLE creatFile(void); 
long WriteBuffer(HANDLE); 
char * GetBuffer(void); 

void main(void) 
{ 
HANDLE hFile; 
printf("CreateFile: "); 
hFile = creatFile(); 
if(hFile != NULL) 
    { 
    WriteBuffer(hFile); 
    FlushFileBuffers(hFile); 
    } 
CloseHandle(hFile); 
printf("\n\rDone"); 
getchar(); 
} 

HANDLE creatFile(void) 
{ 
HANDLE hFile; 
LPCWSTR sFileName = L"\\\\.\\E:"; 
DWORD dwDesiredAccess = GENERIC_WRITE; 
DWORD fShareMode = FILE_SHARE_WRITE | FILE_SHARE_WRITE; 
DWORD fCreationDisposition = OPEN_EXISTING; 
DWORD fFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; 

hFile = CreateFile(sFileName, dwDesiredAccess,fShareMode, 
    NULL, fCreationDisposition, fFlagsAndAttributes, 
    NULL); 

if (hFile == INVALID_HANDLE_VALUE) 
{ 
    hFile = NULL; 
    printf("INVALID_HANDLE_VALUE: "); 

    switch (GetLastError()) 
       { 
    case 5: 
     printf("\n\r Administrative Account required to run this program\n\r"); 
     break; 
    case 87: 
     printf("\n\r Invalid Parameter in CreateFile Call \n\r"); 
     break; 
    default: 

     printf("Error %d\n",GetLastError()); 
     break; 
    } 




    return NULL; 
} 
else 
{ 
    printf("Attached -> %d\n\r",hFile); 
    return hFile; 
} 
} 


long WriteBuffer(HANDLE hFile) 
{ 
char *str = GetBuffer(); // x 64 will give us 512 (sector sized buffer) ; 
DWORD bytesWritten; 
long totalBytesWritten = 0; 
long idx = 0; 
int len = strlen(str); 

for(idx = 0; idx < 100000; idx ++) 
{ 

    if(WriteFile(hFile, str, 512 * sizeof(char), &bytesWritten, NULL)) 
    { 

     totalBytesWritten += bytesWritten; 
     printf("Sectors Written : %d\r",idx+1); 
    } 
    else 
    { 
     int le = GetLastError(); 
     printf("Last Error : %d\r",GetLastError()); 
     break; 
    } 
} 
printf("\n\r"); 
printf("Bytes Written: %d\n\r", totalBytesWritten); 
printf("Handle -> %d\n\r",hFile); 
return totalBytesWritten; 
} 

char * GetBuffer(void) 
{ 
int i = 0, idx = 0; 
const char * cstr_init = "ERASED1 "; 
char *buffer = (char*)malloc(512); 
char word2[512]; 

for (idx = 0; idx < 512; idx+=8) { 
    for (i = 0; i < 8; i++) { 
     buffer[idx+i] = cstr_init[i]; 
     if(strlen(buffer) == 512) 
      break; 
    } 
} 


return buffer; 
} 

문제점을 :

  1. 숯불 * GetBuffer는 16 바이트의 외부 데이터를 가지고 . WriteFile을 수정하여 버퍼가 실제로 보유하고있는 512 개의 문자 (528 대신) 만 쓰도록했습니다. 그것이 16 후 실패하지 않도록

    1. 가 어떻게의 WriteFile을 해결합니까 : -

    2. 서면의 16 개 섹터 이후의 WriteFile는 GetLastError = 5 (액세스 거부)

    질문 실패 섹터 및 ...

  2. GetBuffer는 실제로 528이 아닌 512 버퍼를 생성하도록 어떻게 수정합니까?

노트 응용 프로그램은 ANSI C이며, 프로그램은 관리자로 실행되고있다.

답변

0

나는 질문이 문제를 해결 할 수 없습니다 - 내가 좋아하는 것 방법. 그러나 528 바이트의 버퍼에서 512 바이트를 쓰도록 WriteFile에게 알려줌으로써 원하는 결과를 얻었습니다. 질문 1과 같습니다.

디스크 드라이브에 파일 시스템이 있기 때문에 Windows OS는이 사실을 인식하고 전체 드라이브에 쓰지 못하게합니다. 내가해야 할 일은 사실 드라이브를 잠그면 드라이브에 대한 독점적 인 액세스 권한이 부여됩니다.

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

HANDLE creatFile(void); 
long WriteBuffer(HANDLE); 
char * GetBuffer(void); 

void main(void) 
    { 
HANDLE hFile; 
printf("CreateFile: "); 
hFile = creatFile(); 
if(hFile != NULL) 
{ 
    WriteBuffer(hFile); 
    FlushFileBuffers(hFile); 
} 
CloseHandle(hFile); 
printf("\n\rDone"); 
getchar(); 
} 

HANDLE creatFile(void) 
{ 
HANDLE hFile; 
LPCWSTR sFileName = L"\\\\.\\E:"; 
DWORD dwDesiredAccess = GENERIC_WRITE; 
DWORD fShareMode = FILE_SHARE_WRITE | FILE_SHARE_WRITE; 
DWORD fCreationDisposition = OPEN_EXISTING; 
DWORD fFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; 
BOOL bResult = FALSE;     // results flag 
LPDWORD lpBytesReturned = 0; 

hFile = CreateFile(sFileName, dwDesiredAccess,fShareMode, 
    NULL, fCreationDisposition, fFlagsAndAttributes, 
    NULL); 

if (hFile == INVALID_HANDLE_VALUE) 
{ 
    hFile = NULL; 
    printf("INVALID_HANDLE_VALUE: "); 

    switch (GetLastError()) 
    { 
    case 5: 
     printf("\n\r Administrative Account required to run this program\n\r"); 
     break; 
    case 87: 
     printf("\n\r Invalid Parameter in CreateFile Call \n\r"); 
     break; 
    default: 

     printf("Error %d\n",GetLastError()); 
     break; 
    } 




return NULL; 
} 
else 
{ 
    printf("Attached -> %d\n\r",hFile); 
// HERE I JUST ADD THE FSCTL_LOCK_VOLUME command to stop Windows preventing me from writing to the drive   
    bResult = DeviceIoControl(hFile,      // device to be queried 
     FSCTL_LOCK_VOLUME, // dwIoControlCode 
     NULL, 0,      // no input buffer 
     NULL, 0,   // output buffer 
     lpBytesReturned,       // # bytes returned 
     (LPOVERLAPPED) NULL);   // synchronous I/O 

    return hFile; 
} 
} 


long WriteBuffer(HANDLE hFile) 
{ 
char *str = GetBuffer(); // x 64 will give us 512 (sector sized buffer) ; 
DWORD bytesWritten; 
long totalBytesWritten = 0; 
long idx = 0; 
int len = strlen(str); 

for(idx = 0; idx < 100000; idx ++) 
{ 

    if(WriteFile(hFile, str, 512 * sizeof(char), &bytesWritten, NULL)) 
    { 

     totalBytesWritten += bytesWritten; 
     printf("Sectors Written : %d\r",idx+1); 
    } 
    else 
    { 
     int le = GetLastError(); 
     printf("\n\rLast Error : %d\r",GetLastError()); 
     break; 
    } 
} 
printf("\n\r"); 
printf("Bytes Written: %d\n\r", totalBytesWritten); 
printf("Handle -> %d\n\r",hFile); 
return totalBytesWritten; 
} 

char * GetBuffer(void) 
{ 
const char * cstr_init = "ERASED2 "; 
const int cstr_init_len = strlen(cstr_init); 
char *buffer = (char*)malloc(513); 
int i; 
for (i = 0; i < 512; i+=8) { 
    memcpy(buffer+i, cstr_init, cstr_init_len); 
    // Or strcpy(buffer+1, cstr_init); 
    // Or strcat(buffer, cstr_init); // Inefficient because each call runs from buffer[0] to find a '\0' for where to start appending 
} 
return buffer; 
} 

나중에 참조 할 수 있도록 드라이브에 직접 쓰려면 먼저 볼륨을 잠그는 것이 중요합니다. 위의 코드에서 메모리 누수가 있음을 알고 있습니다. 그러나 드라이브에 데이터를 쓰는 학습 연습으로 나는 귀찮은 사람이 아닙니다. 코드가 정리되어 .dll로 작성됩니다.

0

INT 유형은 부호없는 0 - 65536의 2 바이트 숫자 일 수 있습니다. 모든 INT 유형을 LONG (long)으로 바꾸십시오. ... 어떤 컴파일러 환경을 사용하고 있는지 잘 모르겠습니다.이 변경 사항이 적용되지 않을 수 있습니다.

+0

또한 512 버퍼의 끝 부분에 char 0 문자를 추가하여 513 위치에 추가하십시오. char 값을 0으로 유지하려면 버퍼 크기를 513 이상으로 늘리십시오. 문자열) 문자 (GetBuffer) – Grantly

+0

사용되는 유일한 int 값은 최대 528입니다 (512/513이어야 함). 따라서 환경 (x64)에 관계없이 아무런 차이가 없습니다. –

+0

WriteBuffer의 첫 번째 예제가 아닙니다. INT는 10000 ...으로 증가하고 strlen() 값을 유지하는 데 사용됩니다. 생각했던 첫 번째 예에서 이미 수정되었습니다. 환경은 아무런 문제가 없으며 컴파일러와 설정 만 중요합니다. – Grantly

1

WriteFile()으로 오류를 말할 수는 없지만, 문자열 작업에 문제가 있습니다.

C 문자열은 null로 종료됩니다. 즉, 문자열 리터럴 "abc"은 실제로는 {'a','b','c','\0'}과 같은 문자 배열입니다. str...() 작업은 모두이 사실에 의존합니다. 문자열의 길이에 저장된 정보는 없으며 '\0'으로 끝날 것으로 예상됩니다.

귀하의 GetBuffer() 기능 향상 :

char * GetBuffer(void) 
{ 
    int i = 0, idx = 0; 
    const char * cstr_init = "ERASED1 "; 
    char *buffer = malloc(513); // Space for a '\0' 

    for (idx = 0; idx < 512; idx+=8) { 
     for (i = 0; i < 8; i++) { 
      buffer[idx+i] = cstr_init[i]; 
     } 
    } 
} 
당신은 그것이 '\0' 찾기 때문 strlen()에 대한 이상한 결과를 얻고 있었다 단 하나의 528에서 바이트를 발견했다

는, malloc으로 할당 된 512 바이트의 읽기 외부는 정의되지 않은 동작을 호출하는, 당신은 513 바이트에서 '\ 0'을 발견 할 수 있었고, 찾지 못했습니다.

GetBuffer()을 호출 한 후에는 free()char *이 반환되었습니다. 이는 메모리가 누락되어 해당 컨텍스트 외부에서 손실 되었기 때문에 발생합니다. 또한, GetBuffer()의 더욱 향상된 기능은 다음과 같습니다

char * GetBuffer(void) 
{ 
    const char * cstr_init = "ERASED1 "; 
    const int cstr_init_len = strlen(cstr_init); 
    char * buffer = calloc(1,513); // Guaranteed zeroed 
    int i; 
    for (i = 0; i < 512; i+=8) { 
     memcpy(buffer+i, cstr_init, cstr_init_len); 
     // Or strcpy(buffer+1, cstr_init); 
     // Or strcat(buffer, cstr_init); // Inefficient because each call runs from buffer[0] to find a '\0' for where to start appending 
    } 
    return buffer; 
} 
+0

이 두 함수는 여전히 528 바이트를 반환하며 마지막 문자는 " –

+1

"입니다. @DaveGordon'malloc()'대신'calloc()'호출을 사용 했습니까? if 당신은'malloc()'을 사용했고, 마지막에는'buffer [512] = '\ 0';'를 사용했다. 문자열 버퍼의 길이를 다시 계산할 수있는 유일한 방법은' '\ 0 '' 문자를 살펴 보는 것입니다. 하나라도 존재하지 않는다면,'strlen()'과 같은 함수는' '\ 0' '을 발견하고 그 길이를 잘못보고 할 때까지 당신이 소유하지 않은 메모리에서 계속 읽습니다. – Macattack

+0

죄송합니다 calloc 변경을 놓친 - 여전히 malloc 사용했습니다. 그게 내 관심을 가져 주셔서 감사합니다! –