Click to See Complete Forum and Search --> : downloading binary files over HTTP
hellowonn
May 26th, 2008, 05:16 AM
I wrote a c++ function to send a GET request with winsock, but when i send it to a .exe or any other binary file, it comes out all messed up. I'm storing the result of the request, the file data in a string, then writing it to a file with fstream. Is there some other way you have to do it ?
Atheist
May 26th, 2008, 05:26 AM
Could you show the code you're using to write the response to a file?
hellowonn
May 26th, 2008, 06:28 AM
#include <iostream>
#include <fstream>
#include <winsock.h>
#include <string>
#pragma comment(lib, "wsock32.lib")
#pragma warning (disable:4786)
using namespace std;
hostent* hostinfo;
SOCKET SSocky;
sockaddr_in sockAddr;
string fGetReq(string sType,string sUrl);
string fPostReq(string sUrl,string sPostData);
int fCountString(string sString,string sFind);
int main(int argc,char* argv[])
{
WSADATA wsaData;
if(WSAStartup(MAKEWORD(1,1), &wsaData)!=0){
if(WSAStartup(MAKEWORD(2,2), &wsaData)!=0){
WSACleanup();
exit(0);
}
}
string sUrl,sOutFile,sContent;
sUrl = "http://www.willem.org/ZIP/29C0x0.zip"; //Some random ZIP found with google..
sOutFile = "29c0x0.zip";
sContent = fGetReq("GET",sUrl);
if(sContent.length()){
ofstream mofiz;
mofiz.open(sOutFile.c_str(),ios::binary);
mofiz.write(sContent.c_str(),sContent.length());
//cout << sContent << endl;
mofiz.close();
mofiz.clear();
}
else{
cout << "[+] No data was downloaded!" << endl;
}
return 0;
}
string fGetReq(string sType,string sUrl)
{
if(sUrl.substr(0,7) == "http://" && (fCountString(sUrl,"/")>2)){
string sHost,sPage,sRequest,sContent;
char cContent[256];
sUrl.replace(0,7,"");
sHost = sUrl.substr(0,sUrl.find("/"));
sPage = sUrl.substr(sUrl.find("/"));
sRequest = sType + " " + sPage + " HTTP/1.1\r\n";
sRequest += "Host: " + sHost + "\r\n";
sRequest += "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14\r\n";
sRequest += "Accept: *\r\n";
sRequest += "Connection: Close\r\n\r\n";
SSocky = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
hostinfo = gethostbyname(sHost.c_str());
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(80);
sockAddr.sin_addr.S_un.S_addr = inet_addr(inet_ntoa(*((struct in_addr *)hostinfo->h_addr)));
if (connect(SSocky, (sockaddr*)(&sockAddr), sizeof(sockAddr))==INVALID_SOCKET){
closesocket(SSocky);
WSACleanup();
return NULL;
}
else{
send(SSocky,sRequest.c_str(),sRequest.length(),0);
while(int iBytes = recv(SSocky,cContent,sizeof(cContent),0)){
cContent[sizeof(cContent)] = '\0';
sContent += cContent;
memset(cContent,'\0',sizeof(cContent));
}
return sContent;
}
}
return NULL;
}
int fCountString(string sString,string sFind){
unsigned int iCount,iFound=0;
for(iCount=sString.find(sFind, 0);iCount!=string::npos;iCount=sString.find(sFind, iCount)){
iFound++;
iCount++;
}
return iFound;
};
Heres a random file i found to DL:
http://www.willem.org/ZIP/29C0x0.zip
Download that with my code above ^^ then compare it do that.
It looks like binary data.. but just kinda wrong.
Oh, and the headers get written as well, im going to write a function to parse it and return either headers/content, once i get this figured out.
Atheist
May 26th, 2008, 06:33 AM
It looks like you are writing the entire response to the file, including the response headers?
Also, why are you setting this inside the receive loop:
cContent[sizeof(cContent)] = '\0';
hellowonn
May 26th, 2008, 06:44 AM
It looks like you are writing the entire response to the file, including the response headers?
Also, why are you setting this inside the receive loop:
cContent[sizeof(cContent)] = '\0';
yeah i know im writing the headers as well, I open it with ultraedit and take it out.
I dont even know why i have that line in there.
Atheist
May 26th, 2008, 06:47 AM
I'd say that you remove that line inside the loop, and only return whatever comes after the headers (the 2 line breaks), and I think it'll work better.:)
hellowonn
May 26th, 2008, 07:32 AM
removing that isnt going to help , its like the encoding is different or something.
Atheist
May 26th, 2008, 07:33 AM
But wouldnt it be overwriting whatever was read from the response with a 0 on each 256th byte?
hellowonn
May 26th, 2008, 08:00 AM
Sorreh, I didn't mean that, I meant removing the headers, I removed that line. But yeah, can you just try it out for yourself and you might be able to see what I mean by it not being correct?
Atheist
May 26th, 2008, 08:30 AM
Ah, I think i know whats going on, you're appending the entire char array to sContents in each iteration, even if it doesnt necessarily gets entirely filled (in the last iteration),
Here's my working modification of your code. Note that this is a pretty unefficent way of parsing out the body of the response, you could just read each header line one by one until you find the Content-Length header, get the length of the body, and then read that many bytes after the \r\n\r\n sequence.
#include <iostream>
#include <fstream>
#include <winsock.h>
#include <string>
#pragma comment(lib, "wsock32.lib")
#pragma warning (disable:4786)
using namespace std;
hostent* hostinfo;
SOCKET SSocky;
sockaddr_in sockAddr;
string fGetReq(string sType,string sUrl);
string fPostReq(string sUrl,string sPostData);
int fCountString(string sString,string sFind);
string getBody(string response);
int main(int argc,char* argv[])
{
WSADATA wsaData;
if(WSAStartup(MAKEWORD(1,1), &wsaData)!=0){
if(WSAStartup(MAKEWORD(2,2), &wsaData)!=0){
WSACleanup();
exit(0);
}
}
string sUrl,sOutFile,sContent, sBody;
sUrl = "http://www.vbforums.com/images/logo.gif"; //Some random ZIP found with google..
sOutFile = "vbf.gif";
sContent = fGetReq("GET",sUrl);
if(sContent.length()){
ofstream mofiz;
sBody = getBody(sContent);
mofiz.open(sOutFile.c_str(),ios::binary);
mofiz.write(sBody.c_str(),sBody.length());
//cout << sContent << endl;
mofiz.close();
mofiz.clear();
}
else{
cout << "[+] No data was downloaded!" << endl;
}
return 0;
}
string fGetReq(string sType,string sUrl)
{
if(sUrl.substr(0,7) == "http://" && (fCountString(sUrl,"/")>2)){
string sHost,sPage,sRequest,sContent;
char cContent[8192];
sUrl.replace(0,7,"");
sHost = sUrl.substr(0,sUrl.find("/"));
sPage = sUrl.substr(sUrl.find("/"));
sRequest = sType + " " + sPage + " HTTP/1.1\r\n";
sRequest += "Host: " + sHost + "\r\n";
sRequest += "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14\r\n";
sRequest += "Accept: *\r\n";
sRequest += "Connection: Close\r\n\r\n";
SSocky = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
hostinfo = gethostbyname(sHost.c_str());
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(80);
sockAddr.sin_addr.S_un.S_addr = inet_addr(inet_ntoa(*((struct in_addr *)hostinfo->h_addr)));
if (connect(SSocky, (sockaddr*)(&sockAddr), sizeof(sockAddr))==INVALID_SOCKET){
closesocket(SSocky);
WSACleanup();
return NULL;
}
else{
send(SSocky,sRequest.c_str(),sRequest.length(),0);
while(int iBytes = recv(SSocky,cContent,sizeof(cContent),0)){
sContent.append(cContent, iBytes);
}
return sContent;
}
}
return NULL;
}
string getBody(string response){
int bodyIndex;
bodyIndex = response.find("\r\n\r\n") + 4;
return response.substr(bodyIndex);
}
int fCountString(string sString,string sFind){
unsigned int iCount,iFound=0;
for(iCount=sString.find(sFind, 0);iCount!=string::npos;iCount=sString.find(sFind, iCount)){
iFound++;
iCount++;
}
return iFound;
}
hellowonn
May 27th, 2008, 06:12 AM
Thanks, works fine now. Heres what i use to get either content/headers.
string fReadContent(string sHeaders,string sFind)
{
int iF;
if(sFind == "headers"){
iF = sHeaders.find("\r\n\r\n");
return sHeaders.substr(0,iF+4);
}
if(sFind == "content"){
iF = sHeaders.find("\r\n\r\n");
return sHeaders.substr(iF+4,sHeaders.length());
}
else{
return 0;
}
}
vbforums.com
Copyright Internet.com Inc., All Rights Reserved.