Unveiling of Epsilon Anti-Virus

Pages: 12345... 10
closed account (G309216C)
Thanks! Script Coder for positive attitude, wow 1100 posts.

@Catfish4
Also I said I will be releasing code snippets of large modules.
Besides again using the word Backdoor rootkit is not correct either it is just backdoor with a rootkit not backdoor rootkit becuase rootkit is a software which hides it self and rootkits are not malwares. so using phrase backdoor rootkit is just saying it just hides it self without doing nothing , no stealing nothing. So use the words properly and understand them before using them

Sorry it look bloody rude but I am not being rude, I hate when people use Security related words wrongly and create a new random phrase.

Uhm, yeah, when you say Incoherent, at least in Italy, it means you have a single opinion, and a second later you have a completely different one which breaks the first opinion.

But I think you understood what I meant, you can now get back on the topic :d
closed account (G309216C)
Hi,

Back on topic, As script coder told that if none of you don't trust the program use Vm-Ware or some virtualization software.
Normally, I would suggest one of you to first download and run it in virtual computer than you can show the results, so if it is malicious or not. That way it can be proved safe from any member.

Thanks!
closed account (S6k9GNh0)
Running in a VM isn't an exact way to prove whether something is malicious or not. The only way to truly tell is if you can see the actual logic behind it.
closed account (N36fSL3A)
Does your program read files from a "vault" located on the harddrive?
Some viruses can detect virtual machines and change their behaviour anyway. It's not even difficult: one trivial way to check is to get the CPUID brand string because Qemu, for example, uses something like "QEMU Virtual CPU". All the virus has to do is test for known emulator names, plus words like "virtual" and "emulated" in the brand string.

[edit] Here's example code of detecting common software emulators like Qemu.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <cctype>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

enum { EAX, EBX, ECX, EDX };

static void cpuid(std::uint32_t(& regs)[4]) 
{
    asm volatile(
        "cpuid" 
        :"=a"(regs[EAX]), "=b"(regs[EBX]),
         "=c"(regs[ECX]), "=d"(regs[EDX]) 
        : "a"(regs[EAX]),  "b"(regs[EBX]),
          "c"(regs[ECX]),  "d"(regs[EDX])
    );
} 

static std::string get_brand_string(std::uint32_t part)
{
    constexpr std::uint32_t request = 0x80000002;
    static char string[16 + 1];
    std::uint32_t regs[] = {request + part - 1, 0, 0, 0};
    cpuid(regs);
    strncpy(string + 16 * (part - 1) +  0, (const char*)&regs[EAX], 4);
    strncpy(string + 16 * (part - 1) +  4, (const char*)&regs[EBX], 4);
    strncpy(string + 16 * (part - 1) +  8, (const char*)&regs[ECX], 4);
    strncpy(string + 16 * (part - 1) + 12, (const char*)&regs[EDX], 4);
    return std::string(string);
}

static std::string get_brand_string()
{
    std::ostringstream ss;
    ss << get_brand_string(1) << get_brand_string(2) << get_brand_string(3);
    return ss.str();
}

static std::string s2lower(const std::string& string)
{
    std::ostringstream ss;
    for (char c : string)
        ss << char(std::tolower(c));
    return ss.str();
}

bool test_brand_string()
{
    static const std::vector<std::string> search_strings = {
        // Popular emulator/virtual machine names.
        "bochs", "hydra", "qemu", "virtualbox", "virtualpc", "vmware",
        // General strings.
        "vm", "emulated", "virtual", "box"
    };
    static std::string brand_string = s2lower(get_brand_string());
    for (std::string search_string : search_strings) {
        if (brand_string.find(search_string) != std::string::npos)
            return true;
    }
    return false;
}

bool is_emulated_cpu()
{
    if (test_brand_string())
        return true;
    return false;
}

int main()
{
    std::cout << "Running on" << ((is_emulated_cpu()) ? " emulated " : " real ")
              << "hardware (probably). CPU brand string: " << get_brand_string()
              << std::endl;
    return 0;
}


(On my PC) Running on real hardware (probably). CPU brand string: AMD Phenom(tm) II X4 980
Processor
(On QEMU) Running on emulated hardware (probably). CPU brand string: QEMU Virtual CPU version 0.9.0
Last edited on
closed account (G309216C)
Your right, but we don't need to virtualize the computer than what you do is just hook important functions such as NtCreateFile(), NtCopyFile() , and other functions which may lead to Viruses getting out of control, this would be better right. Or what you do if you really want to know is to get a back up then install my AV then try it that way if it is a worm\Malware you can reformat computer completely also backup MBR. Obviously there are plenty of ways.

Next the above code does not work.
Last edited on
closed account (3qX21hU5)
I am very confused about this thread. For one you say you are unveiling you AV program and then all you provide is a screenshot of a GUI? Then you also want feedback on your program but again only provide a screenshot of a GUI.

How are we suppose to give you feedback when we have nothing to look at (The code)? I mean the GUI looks good and is colorful but that is all we can really give feedback on.

I don't know maybe I just don't get why people tend to ask for feedback but then refuse to release the actual code for the program or atleast provide the program itself. I mean if you weren't ready to release aworking copy or the full code or at least snippets of code why not just wait until you are ready and then post a thread like this?
closed account (S6k9GNh0)
chrisname, issue appears to be on line 60. I don't quite understand how you generated the brand string so I can't help you on that... but it look suspicious.
@ computerquip: he used the CPUID instruction and fed it 0x80000002, 0x80000003, 0x80000004 through some overcomplicated code (in my opinion).

http://en.wikipedia.org/wiki/CPUID#EAX.3D80000002h.2C80000003h.2C80000004h:_Processor_Brand_String
@SpaceWorm
It worked on my PC (g++ 4.7.3 on Cygwin i686 on Windows 7 x86-64). It was only for demonstration so naturally I didn't test it strenuously (I didn't really even run it on Qemu, I just made get_brand_string return Qemu's brand string). With just that simple test, it will fail in a lot of cases (such as on any virtual machine that doesn't return an obviously-fake brand string, as well as any hypervisor or hardware VM) and might even get false positives (on any real CPU that returns a brand string containing any of the words it searches for) and it also won't work on old CPUs that don't support the extended CPUID functions,

@computerquip
What's suspicious about it? It's just searching for a string in another string.

The brand string comes from the CPU itself. You put a value in EAX, execute the CPUID instruction, and then the CPU changes the values of some of the general purpose registers. In this case, it's returning an ASCII string. Each register E*X is 4 bytes so each one contains 4 ASCII characters for a total of 16 each time you call it. The total string is 16 * 3 = 48 bytes long so you have to do it three times with three consecutive values in EAX.

@Catfish4
How is it overcomplicated? The way I wrote it is general and extensible. I can add extra tests without hassle and I can reuse the cpuid and get_brand_string functions without any changes (actually I wrote them ages ago in a piece of code that uses almost all of the CPUID requests, I just converted them from C to C++). It can be simplified into this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <cctype>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>

static std::string s2lower(const std::string& string)
{
    std::ostringstream ss;
    for (char c : string)
        ss << char(std::tolower(c));
    return ss.str();
}

int main()
{
    static char brand_string[48 + 1];
    std::uint32_t eax, ebx, ecx, edx;
    bool emulated = false;
    asm volatile("cpuid":"=a"(0x80000002):"a"(eax), "b"(ebx), "c"(ecx), "d"(edx));
    strncpy(brand_string +  0, (const char*)eax, 4);
    strncpy(brand_string +  4, (const char*)ebx, 4);
    strncpy(brand_string +  8, (const char*)ecx, 4);
    strncpy(brand_string + 12, (const char*)edx, 4);
    asm volatile("cpuid":"=a"(0x80000003):"a"(eax), "b"(ebx), "c"(ecx), "d"(edx));
    strncpy(brand_string + 16, (const char*)eax, 4);
    strncpy(brand_string + 20, (const char*)ebx, 4);
    strncpy(brand_string + 24, (const char*)ecx, 4);
    strncpy(brand_string + 28, (const char*)edx, 4);
    asm volatile("cpuid":"=a"(0x80000004):"a"(eax), "b"(ebx), "c"(ecx), "d"(edx));
    strncpy(brand_string + 32, (const char*)eax, 4);
    strncpy(brand_string + 36, (const char*)ebx, 4);
    strncpy(brand_string + 40, (const char*)ecx, 4);
    strncpy(brand_string + 44, (const char*)edx, 4);
    for (const std::string& search_string : search_strings) {
        if (s2lower(brand_string).find(s2lower(search_string)) != std::string::npos) {
            emulated = true;
            break;
        }
    }
    std::cout << "Running on " << ((emulated) ? "emulated" : "real")
              << " hardware (probably). CPU brand string: " << brand_string
              << std::endl;
    return 0;
}

but now, if I want to reuse or extend any code, I have to split it up into functions again. And I haven't really even decreased the amount of code or made it more readable. All that's really changed is that the flow of control is more linear - big deal.

(note: I haven't tested this version at all, not even to see if it compiles so I might've made mistakes).
@ chrisname: I only stated an opinion, formed from a very shallow pass. If I actually tried to rewrite it myself, I concede I probably couldn't do much better and yet... array references?

At the very least, my gut feeling tells me you should have used memcpy() instead of strncpy(). The latter just doesn't feel right, again in my opinion.

Now back to the topic: I'm still waiting to see if SpaceWorm releases the source code.
closed account (G309216C)
Hi,

I am going to be releasing some of the code not specified because I need to make my mind up, till day after tomorrow, sorry guys but I am not going to release all the source because I don't want to give the whole project away.

Or maybe I may upload it to Github and slowly release it code by code that way it will get regular visits and also will be easier for me.
closed account (S6k9GNh0)
@ chrisname, the code segfaults on g++ and clang++.
closed account (N36fSL3A)
I wrote:
Does your program read files from a "vault" located on the harddrive?
sorry guys but I am not going to release all the source because I don't want to give the whole project away.

OK then, please answer this question: without the full source (leaving us unable to compile the executable ourselves) how do we know if the executable you provide is not malicious?

I don't know about others, but I'm really bad at deciphering machine code.
@Catfish
Fair enough.

@computerquip
That's odd, it doesn't do so on my computer with g++ 4.7.3. Ehh... I'm not going to bother looking into it because it was just a throwaway demonstrative piece of code.
That's odd, it doesn't do so on my computer with g++ 4.7.3.


Undefined behavior is strange like that.

1
2
3
4
5
6
7
    static char string[16 + 1];
    std::uint32_t regs[] = {request + part - 1, 0, 0, 0};
    cpuid(regs);
    strncpy(string + 16 * (part - 1) +  0, (const char*)&regs[EAX], 4);
    strncpy(string + 16 * (part - 1) +  4, (const char*)&regs[EBX], 4);
    strncpy(string + 16 * (part - 1) +  8, (const char*)&regs[ECX], 4);
    strncpy(string + 16 * (part - 1) + 12, (const char*)&regs[EDX], 4);
closed account (N36fSL3A)
That's cool, totally ignore my question.
SpaceWorm has not responded between when you re-posted the question he accidentally skimmed over and when you complained that he was ignoring it. You might as well say he's ignoring Catfish as well.
Last edited on
Pages: 12345... 10