I want to get all modules from another process. But it returns absurd values. Program stay in do-while loop for one time. After that exits from do-while loop.
I can't find where is the mistake - how can I fix this? I know that program must be in do-while loop for several time but it don't.
NTSTATUS Status;
PROCESS_BASIC_INFORMATION pbi;
ULONG ReturnLength;
Status = NtQueryInformationProcess(
INJECTOR_INFO.process.processHandle,
ProcessBasicInformation,
&pbi,
sizeof(PROCESS_BASIC_INFORMATION),
&ReturnLength);
if (!NT_SUCCESS(Status)) {
printf("NtQueryInformationProcess failed.(pbi)\n");
return;
}
else {
PLIST_ENTRY HeadEntry = pbi.PebBaseAddress->LoaderData->InMemoryOrderModuleList.Flink;
PLIST_ENTRY nextEntry = pbi.PebBaseAddress->LoaderData->InMemoryOrderModuleList.Blink;
DWORD dwBytesRead = 0;
PLDR_MODULE pLdrModule = nullptr;
LDR_MODULE LdrModule;
do
{
LDR_DATA_TABLE_ENTRY LdrEntry;
PLDR_DATA_TABLE_ENTRY Base = CONTAINING_RECORD(HeadEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
if (NT_SUCCESS(Status = NtReadVirtualMemory(INJECTOR_INFO.process.processHandle, Base, &LdrEntry, sizeof(LdrEntry), &dwBytesRead)))
{
if (dwBytesRead != sizeof(LdrEntry)) {
printf("length doesn't match");
return;
}
char* pLdrModuleOffset = reinterpret_cast<char*>(HeadEntry) - sizeof(LIST_ENTRY);
if (!NT_SUCCESS(Status = NtReadVirtualMemory(INJECTOR_INFO.process.processHandle, pLdrModuleOffset, &pLdrModule, sizeof(pLdrModule), &dwBytesRead))) {
printf("pLdrModuleOffset doesn't read"); return;
}else if (dwBytesRead != sizeof(pLdrModule)) { printf("pLdrModule length doesn't match"); return; }
if (!NT_SUCCESS(Status = NtReadVirtualMemory(INJECTOR_INFO.process.processHandle, pLdrModule, &LdrModule, sizeof(LdrModule), &dwBytesRead))) {
printf("pLdrModule doesn't read"); return;
}else if (dwBytesRead != sizeof(LdrModule)) { printf("LdrModule length doesn't match"); return; }
if (LdrEntry.DllBase)
{
printf("BaseAddress: %p\n", LdrModule.BaseAddress);
printf("Reference Count: %d\n", LdrModule.LoadCount);
}
HeadEntry = LdrEntry.InMemoryOrderLinks.Flink;
}
else { printf("LDR_DATA_TABLE_ENTRY doesn't read"); return; }
} while (HeadEntry != nextEntry);
}
I put breakpoint on !NT_SUCCESS(Status) after NtQueryInformationProcess for values of variables:
Values after NtQueryInformationProcess
Another breakpoint for values of variables in do while for the end of the first cycle:
Values for the end of the first cycle
You are querying a remote process for it's PROCESS_BASIC_INFORMATION, but then you proceed to follow the pointers in your own process:
PLIST_ENTRY HeadEntry = pbi.PebBaseAddress->LoaderData->InMemoryOrderModuleList.Flink;
For this to work, read the PEB from the remote process (from pbi.PebBaseAddress),
then read the LoaderData from the remote process (PEB.LoaderData).
Then, follow the InMemoryOrderModuleList (again, read the data from the remote process).
At this point you can iterate over the entire list, by reading each entry from the remote process.
Related
I am trying to rename files from kernel.
with this api https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-zwsetinformationfile
NTSTATUS Files::RenameFile(WCHAR* OriginalName, WCHAR* NewName)
{
// msdn says driver must be at IRQL PASSIVE_LEVEL to make calls to ZwSetInformationFile
if (KeGetCurrentIrql() != PASSIVE_LEVEL)
{
printf("IRQL invalid\n");
return STATUS_INVALID_LEVEL;
}
// Open handle to file , providing OriginalName with full path, example: "\\DosDevices\\C:\\named_file.txt"
// also to be able to rename files u delete the DELETE permission, but i assume with GENERIC_ALL is already giving me enough of them
auto FileHandle = Files(OriginalName, Files::OpenExisting, GENERIC_ALL, 0);
if (FileHandle.CreationStatus != STATUS_SUCCESS)
{
printf("Failed to open handle to file %ws. ERR: 0x%x\n", OriginalName, FileHandle.CreationStatus);
return FileHandle.CreationStatus;
}
IO_STATUS_BLOCK ioStatusBlock;
// msnd info for ZwSetInformatonFile when using FileRenameInformation class says that size must be the size of the
// structure + size of new name in bytes
const auto size = sizeof(FILE_RENAME_INFORMATION) + sizeof(NewName);
// allocate resources for struct
const auto rename_info = static_cast<PFILE_RENAME_INFORMATION>(ExAllocatePool(PagedPool, size));
if(rename_info == nullptr)
{
printf("Failed allocating rename info structure\n");
FileHandle.Close();
return STATUS_INSUFFICIENT_RESOURCES;
}
memset(rename_info, 0, size);
wcscpy(rename_info->FileName, NewName);
rename_info->FileNameLength = sizeof(NewName);// size in bytes
rename_info->RootDirectory = nullptr; // msnd: must be null if the filename is the absolute path
rename_info->ReplaceIfExists = false; // i dont want to replace if exissts
const auto status = ZwSetInformationFile(FileHandle.hFile, &ioStatusBlock, rename_info, size, FileRenameInformation);
// free resources
ExFreePool(rename_info);
FileHandle.Close();
// ZwSetInformationFile fails with 0xc0000034 STATUS_OBJECT_NAME_NOT_FOUND
if(status != STATUS_SUCCESS)
{
printf("0x%x : %ws\n", status, rename_info->FileName); // -> 0xc0000034 : "\\DosDevices\\C:\\renamed_file.txt"
return status;
}
printf("Renamed %ws to %ws\n", OriginalName, NewName);
return STATUS_SUCCESS;
}
i commented a bit of the code, but TLDR; it gives me 0xc0000034 STATUS_OBJECT_NAME_NOT_FOUND.
I followed everything as stated in the MSDN but im always with the same issue, the originalname file does exist in disk since it opens handle succesfully.
any help is appreciated, thanks
I'm trying to implement a very simple API for audio playback using portaudio. I have minimal amount of code needed to play the audio file but I am not getting any errors and/or audio output.
Here is the code,
AudioStream::AudioStream()
{
PaError err = Pa_Initialize();
if (err != paNoError)
SH_LOG_ERROR("PAError: {}", Pa_GetErrorText(err));
}
AudioStream::~AudioStream()
{
PaError err = Pa_Terminate();
if (err != paNoError)
SH_LOG_ERROR("PAError: {}", Pa_GetErrorText(err));
}
int AudioStream::Callback(const void* inputBuffer, void* outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void* userData)
{
// Prevent warnings
(void)inputBuffer;
(void)timeInfo;
(void)statusFlags;
// an AudioFile gets passed as userData
AudioFile* file = (AudioFile*)userData;
float* out = (float*)outputBuffer;
sf_seek(file->file, file->readHead, SF_SEEK_SET);
auto data = std::make_unique<float[]>(framesPerBuffer * file->info.channels);
file->count = sf_read_float(file->file, data.get(), framesPerBuffer * file->info.channels);
for (int i = 0; i < framesPerBuffer * file->info.channels; i++)
*out++ = data[i];
file->readHead += file->buffer_size;
if (file->count > 0)
return paContinue;
else
return paComplete;
}
AudioFile AudioStream::Load(const char* path)
{
AudioFile file;
std::memset(&file.info, 0, sizeof(file.info));
file.file = sf_open(path, SFM_READ, &file.info);
return file;
}
bool AudioStream::Play(AudioFile* file)
{
m_OutputParameters.device = Pa_GetDefaultOutputDevice();
m_OutputParameters.channelCount = file->info.channels;
m_OutputParameters.sampleFormat = paFloat32;
m_OutputParameters.suggestedLatency = Pa_GetDeviceInfo(m_OutputParameters.device)->defaultLowOutputLatency;
m_OutputParameters.hostApiSpecificStreamInfo = nullptr;
// Check if m_OutputParameters work
PaError err = Pa_IsFormatSupported(nullptr, &m_OutputParameters, file->info.samplerate);
if (err != paFormatIsSupported)
{
SH_LOG_ERROR("PAError: {}", Pa_GetErrorText(err));
return false;
}
err = Pa_OpenStream(&m_pStream,
nullptr,
&m_OutputParameters,
file->info.samplerate,
file->buffer_size,
paClipOff,
&AudioStream::Callback,
file);
if (err != paNoError)
{
SH_LOG_ERROR("PAError: {}", Pa_GetErrorText(err));
return false;
}
if (m_pStream)
{
err = Pa_StartStream(m_pStream);
if (err != paNoError)
{
SH_LOG_ERROR("PAError: {}", Pa_GetErrorText(err));
return false;
}
SH_LOG_DEBUG("Waiting for playback to finish..");
while (IsStreamActive()) // <----- this works, but the application freezes until this ends
Pa_Sleep(500);
Stop();
if (IsStreamStopped())
{
SH_LOG_DEBUG("Stream stopped..");
err = Pa_CloseStream(m_pStream);
if (err != paNoError)
{
SH_LOG_ERROR("PAError: {}", Pa_GetErrorText(err));
return false;
}
}
SH_LOG_DEBUG("Done..");
}
return true;
}
bool AudioStream::Stop()
{
PaError err = Pa_StopStream(m_pStream);
if (err != paNoError)
{
SH_LOG_ERROR("PAError: {}", Pa_GetErrorText(err));
return false;
}
else
return true;
}
bool AudioStream::IsStreamStopped()
{
if (Pa_IsStreamStopped(m_pStream))
return true;
else
return false;
}
I noticed that if I add a print statement in the while loop I do get audio output.
// Wait until file finishes playing
while (file->count > 0) { SH_LOG_DEBUG(""); }
Why doesn't it play with a print statement or anything in while loop? Do I have to have something in the while loop?
You've got two flaws that I can see.
One is using what looks like a class method as the callback to PulseAudio. Since PA is a C API, it expects a C function pointer here. It won't call that function with the this pointer set, so you can't have a class method here. But maybe AudioStream::Callback is static? That will work.
Two is that you need to consider that the callback is called in another thread. The compiler does not take that into account when it optimizes the code. As far as it knows, there is nothing in your empty while loop that could possibly change the value of file->count.
Once you call the debug function, it brings in enough code, some probably in libraries that are already compiled, that the compiler can't be sure nothing has modified file->count. Maybe SH_LOG_DEBUG() calls prinf() and then printf() calls AudioStream::Load()? Of course it doesn't, but if the compiler doesn't see the code of printf() because it's already in a library, and your AudioStream object is global, then it's possible. So it actually works like you want.
But even when it works, it's really bad. Because the thread is sitting there busy waiting for the count to stop, hogging the/a CPU. It should block and sleep, then get notified when the playback finishes.
If you want to pass information between threads in a way that works, and also block instead of busy waiting too, look into the C++ concurrency support library. The C++20 std::latch and std::barrier would work well here. Or use a C++11 std::condition_variable.
I have a thread that constantly looks for new data and if the data is not already in the serial buffer, ReadFile and GetOverlappedResult seem to tell me there's data, and that it read it, but not transfer it into my buffer...
func read()
{
if(state == 0)
{
memset(bytes, '\0', sizeof(amount_to_read));
readreturn = ReadFile(h, bytes, amount_to_read,NULL, osReader);
if(readreturn <= 0)
{
errorcode = GetLastError();
if(errorcode != ERROR_IO_PENDING)
{
SetEAIError(ERROR_INTERNALERROR);
return -1;
}
}
}
if (GetOverlappedResult(h, osReader, &dwRead, FALSE) == false)
{
errorcode = GetLastError();
if (errorcode == ERROR_IO_INCOMPLETE || errorcode == 0)
{
if(dwRead > 0)
{
return 1;
}
//timeout
SetEAIError(ERROR_EAITIMEOUT);
return -1;
}
else
{
//other error
SetEAIError(ERROR_WIN_ERROR);
return -1;
}
}
else
{
//read succeded, check if we read the amount required
if(dwRead != amount_to_read)
{
if(dwRead == 0)
{
//nothing read, treat as timeout
SetEAIError(ERROR_EAINOREAD);
return -1;
}
else
{
//memcpy_s(bytes, sizeof(bytes), readbuf, dwRead);
SetEAIError(ERROR_PARTIALREAD);
*_bytesRead = dwRead;
return -1;
}
}
else
{
if(strlen((char*)bytes) == 0)
{
//nothing read, treat as timeout
SetEAIError(ERROR_EAINOREAD);
return -1;
}
//memcpy_s(bytes, sizeof(bytes), readbuf, dwRead);
*_bytesRead = dwRead;
return 0;
}
}
}
This is what the error codes mean:
ERROR_TIMEOUT - switches the state to 1 so that it does not read again, which calls GetOverlappedResult again
INTERNALERROR,ERROR_EAINOREAD - it resets state to 0
ERROR_PARTIALREAD - starts a new read with new amount of bytes to read
If I swtich GetOverlappedResult to blocking (pass TRUE) it works every time.
If I switch my thread to only read when I know there is data there it works every time.
But if there is not data there, when there is data there it seems to "lose" the data, it my read amount parameter dwRead shows the correct number of bytes read (can see it read with a port monitor) but the bytes are not stored in my char*.
I constantly get ERROR_EAINOREAD
What am I doing wrong?
I do not want to use flags, I want to just use ReadFile and GetOverlappedResult, I should be able to accomplish this with the code I have....... I assume
The problem was exactly what was stated the data was getting lost... the REASON it was getting lost is because the bytes parameter passed into the readfile is a local variable in the parents thread. being local it gets re initialized each cycle so after I come into the read again, skip the readfile and go to the overlappedresults, I am now potentially working with a different area of memory
I am trying to use a system of maps to store and update data for a chat server. The application is mutlithreaded and uses a lock system to prevent multiple threads from accessing the data.
The problem is this: when a client is removed individually from the map, it is ok. However, when I try to call multiple closes, it leaves some in the memory. If I at any point call ::clear() on the map, it causes a debug assertion error with either "Iterator not compatible" or similar. The code will work the first time (tested using 80+ consoles connected as a test), but due to it leaving chunks behind, will not work again. I have tried researching ways, and I have written systems to stop the code execution until each process has completed. I appreciate any help so far, and I have attached the relevant code snippets.
//portion of server code that handles shutting down
DWORD WINAPI runserver(void *params) {
runserverPARAMS *p = (runserverPARAMS*)params;
/*Server stuff*/
serverquit = 0;
//client based cleanup
vector<int> tokill;
map<int,int>::iterator it = clientsockets.begin();
while(it != clientsockets.end()) {
tokill.push_back(it->first);
++it;
}
for(;;) {
for each (int x in tokill) {
clientquit[x] = 1;
while(clientoffline[x] != 1) {
//haulting execution until thread has terminated
}
destoryclient(x);
}
}
//client thread based cleanup complete.
return 0;
}
//clientioprelim
DWORD WINAPI clientioprelim(void* params) {
CLIENTthreadparams *inparams = (CLIENTthreadparams *)params;
/*Socket stuff*/
for(;;) {
/**/
}
else {
if(clientquit[inparams->clientid] == 1)
break;
}
}
clientoffline[inparams->clientid] = 1;
return 0;
}
int LOCKED; //exported as extern via libraries.h so it's visible to other source files
void destoryclient(int clientid) {
for(;;) {
if(LOCKED == 0) {
LOCKED = 1;
shutdown(clientsockets[clientid], 2);
closesocket(clientsockets[clientid]);
if((clientsockets.count(clientid) != 0) && (clientsockets.find(clientid) != clientsockets.end()))
clientsockets.erase(clientsockets.find(clientid));
if((clientname.count(clientid) != 0) && (clientname.find(clientid) != clientname.end()))
clientname.erase(clientname.find(clientid));
if((clientusername.count(clientid) != 0) && (clientusername.find(clientid) != clientusername.end()))
clientusername.erase(clientusername.find(clientid));
if((clientaddr.count(clientid) != 0) && (clientaddr.find(clientid) != clientaddr.end()))
clientaddr.erase(clientusername.find(clientid));
if((clientcontacts.count(clientid) != 0) && (clientcontacts.find(clientid) != clientcontacts.end()))
clientcontacts.erase(clientcontacts.find(clientid));
if((clientquit.count(clientid) != 0) && (clientquit.find(clientid) != clientquit.end()))
clientquit.erase(clientquit.find(clientid));
if((clientthreads.count(clientid) != 0) && (clientthreads.find(clientid) != clientthreads.end()))
clientthreads.erase(clientthreads.find(clientid));
LOCKED = 0;
break;
}
}
return;
}
Are you really using an int for locking or was it just a simplification of the code? If you really use an int: this won't work and the critical section can be entered twice (or more) simultaneously, if both threads check the variable before one assigns to it (simplified). See mutexes in Wikipedia for reference. You could either use some sort of mutex provided by windows or boost thread instead of the int.
I am having a problem with a Serial Port communication between Arduino Nano and C++, even though the problem is in C++ side. Basically I want to send integers (or long,...) from the Arduino to a C++ program to be processed.
First I did a test sending information from the Arduino to the computer using Matlab. The Arduino code is pretty simple:
int i = 0;
void setup() {
// start serial port at 9600 bps:
Serial.begin(9600);
establishContact();
}
void loop() {
Serial.println(i);
i=i+1;
delay(10);
}
void establishContact() {
while (Serial.available() <= 0) {
Serial.println('A', BYTE);
delay(10);
}
}
The Matlab side is also simple:
clc;
clear all;
numSec=2;
t=[];
v=[];
s1 = serial('COM3'); % define serial port
s1.BaudRate=9600; % define baud rate
set(s1, 'terminator', 'LF'); % define the terminator for println
fopen(s1);
try % use try catch to ensure fclose
% signal the arduino to start collection
w=fscanf(s1,'%s'); % must define the input % d or %s, etc.
if (w=='A')
display(['Collecting data']);
fprintf(s1,'%s\n','A'); % establishContact just wants
% something in the buffer
end
i=0;
t0=tic;
while (toc(t0)<=numSec)
i=i+1;
t(i)=toc(t0);
t(i)=t(i)-t(1);
v(i)=fscanf(s1,'%d');
end
fclose(s1);
plot(t,v,'*r')
catch me
fclose(s1);
end
My goal is, with C++, do the same that is done in Matlab using fscanf(s1, '%d').
Here is the current code that I am using (C++ code):
void main()
{
HANDLE hSerial;
hSerial = CreateFile(TEXT("COM3"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,//FILE_FLAG_OVERLAPPED,
NULL);
if ( hSerial == INVALID_HANDLE_VALUE)
{
printf("Error initializing handler");
}
else
{
// Set the parameters of the handler to the serial port.
DCB dcb = {0};
dcb.DCBlength = sizeof(dcb);
if ( !GetCommState(hSerial, &dcb) )
{
printf("Error setting parameters");
}
FillMemory(&dcb, sizeof(dcb), 0);
dcb.BaudRate = CBR_9600;
dcb.ByteSize = 8;
dcb.StopBits = ONESTOPBIT;
dcb.Parity = NOPARITY;
if ( !SetCommState(hSerial, &dcb) )
{
// error setting serial port state.
}
// Tell the program not to wait for data to show up
COMMTIMEOUTS timeouts = {0};
timeouts.ReadIntervalTimeout = 0;//20;
timeouts.ReadTotalTimeoutConstant = 0;//20;
timeouts.ReadTotalTimeoutMultiplier = 0;//50;
timeouts.WriteTotalTimeoutConstant = 0;//100;
timeouts.WriteTotalTimeoutMultiplier = 0;//100;
if ( !SetCommTimeouts(hSerial, &timeouts) )
{
printf("Error setting the timeouts");
}
char szBuff[5] = "";
DWORD dwBytesRead = 0;
int i = 0;
char test[] = "B\n";
int maxSamples = 10;
DWORD dwCommStatus;
WriteFile(hSerial, test, 2, &dwBytesRead, NULL);
SetCommMask(hSerial,EV_RXCHAR);
while (i < maxSamples)
{
WaitCommEvent (hSerial, &dwCommStatus, 0);
if (dwCommStatus & EV_RXCHAR)
{
memset(szBuff,0,sizeof(szBuff));
ReadFile(hSerial, LPVOID(szBuff), 4, &dwBytesRead, NULL);
cout<<szBuff;
printf(" - %d - \n", atoi(szBuff));
}
i++;
}
scanf("%d", &i);
CloseHandle(hSerial);
}
}
The goal of my code would be something like num = ReadSerialCOM(hSerial, "%d");
My current C++ code reads the information from the buffer, but there is not an accepted end of line, which implies that my numbers (integers) are received cut.
Eg:
I send 8889 from the Arduino, which places it in the COM port. And the command ReadFile saves '88' into szBuff. At the next iteration '89\n' is saved into sZBuff. Basically I want to avoid to post-process sZBuff to concat '88' and '89\n'.
Anyone?
Thanks!
If I understand your question correctly, one way to avoid having to 'post-process' is to move the pointer passed to ReadFile to the end of the available data, so the ReadFile call is appending to the buffer, instead of overwriting.
Essentially, you would have two pointers. One to the buffer, the other to the end of the data in the buffer. So when your program starts, both pointers will be the same. Now, you read the first 2 bytes. You increment the end-of-data pointer by 2. You do another read, but instead of szBuff, you pass a pointer to the end of the previously read data. You read the next three bytes and you have the complete entry in szBuff.
If you need to wait until some delimiter to mark the end of an entry is received, you could just search the received data for it. If it's not there, you keep reading until you find it. If it is there, you can just return.
// Fill the buffer with 0
char szBuff[256] = {0};
// We have no data in the buffer, so the end of data points to the beginning
// of the buffer.
char* szEndOfData = szBuff;
while (i < maxSamples)
{
WaitCommEvent (hSerial, &dwCommStatus, 0);
if (dwCommStatus & EV_RXCHAR)
{
// Append up to 4 bytes from the serial port to the buffer
ReadFile(hSerial, LPVOID(szEndOfData), 4, &dwBytesRead, NULL);
// Increment the end of data pointer, so it points to the end of the
// data available in the buffer.
szEndOfData += dwBytesRead;
cout<<szBuff;
printf(" - %d - \n", atoi(szBuff));
}
i++;
}
// Output, assuming what you mentioned happens:
// - 88 -
// - 8889 -
If this approach is acceptable to you, it will require a bit more work. For example, you would have to ensure you don't overflow your buffer. When you remove data from the buffer, you'll have to move all of the data after the removed segment to the beginning, and fix the end of data pointer. Alternatively, you could use a circular buffer.
As Hans Passant and dauphic pointed, it doesn't seem to be a general solution for my question. I am writing, though, the code that I was trying to avoid, just in case somebody finds it useful or face the same problem that I had:
int i = 0;
DWORD dwBytesRead = 0;
DWORD dwCommStatus = 0;
char szBuff[2] = "";
int maxRead = 20;
int sizeNum = 1;
int *num = (int*)malloc(maxRead*sizeof(int));
char *currNum;
char *pastNum;
// Write something into the Serial Port to start receive
// information from the Arduino
WriteFile(hSerial, (LPCVOID)"A\0", 1, &dwBytesRead, NULL);
SetCommMask(hSerial, EV_RXCHAR);
// Start reading from the Serial Port
while ( i < maxRead )
{
WaitCommEvent (hSerial, &dwCommStatus, 0);
if (dwCommStatus & EV_RXCHAR) // if a char is received in the serial port
{
ReadFile(hSerial, LPVOID(szBuff), 1, &dwBytesRead, NULL);
if ( szBuff[0] > 47 && szBuff[0] < 58 )
{
sizeNum++;
if (sizeNum ==2)
{
currNum = (char*)malloc(sizeNum*sizeof(char));
strcpy(currNum, szBuff);
} else
{
if (pastNum != NULL)
free(pastNum);
pastNum = currNum;
currNum = (char*)malloc(sizeNum*sizeof(char));
strcpy(currNum, pastNum);
strcpy(currNum+(sizeNum-2)*sizeof(char), szBuff);
}
cout << szBuff<<endl;
} else if (szBuff[0] == '\n' && sizeNum > 1) // end of number
{
num[i] = atoi(currNum);
i++;
sizeNum = 1;
if (currNum!=NULL)
free(currNum);
}
}
}